Posts

Broken, Abandoned, and Forgotten Code, Part 10

Debugging and De-bricking the Netgear R6200 via UART Update: I forgot to credit my former colleague, Tim (@bjt2n3904), for helping me locate the UART header. This project would have been way more challenging without the serial connection. It would have involved desoldering the flash memory chip, probably replacing it with a ZIF socket, and then removing and reprogramming the chip for each iteration of testing. In the previous installment, we filled out the ambit firmware header just enough to satisfy Netgear’s broken UPnP server. We also patched out several ioctl() calls in upnpd in order to test the SetFirmware exploit in emulation.
Read more

Broken, Abandoned, and Forgotten Code, Part 9

In the previous part, we switched gears back to the Netgear R6200 upnpd after spending some time analyzing httpd. The HTTP daemon provided an understanding of how the firmware header is supposed to be constructed. We found a header parsing function in upnpd that was similar to its httpd counterpart. So similar that it has the same memcpy() buffer overflow. This overflow was more interesting this time around, as it did not require authentication. Additionally, we discovered a reference to the “Ambit image” via an error message string. Presumably an ambit image is a firmware format analogous to TRX. In this case, however, the ambit image encapsulates a TRX image.
Read more

Broken, Abandoned, and Forgotten Code, Part 8

In the previous few posts, we spent time reversing how the Netgear R6200’s HTTP daemon parses a firmware header before writing the firmware image to flash. The goal was to work out how the 58-byte firmware header is constructed and how to generate a new one that can replace the header in a stock firmware. In the end we identified the purpose of all but 4 bytes. The regenerated header plus the original TRX firmware image allowed the HTTP daemon, running in emulation, to reach the stage where it would start writing data to the /dev/mtd1 flash partition. Considering this a win, we’ll now circle back to analyzing upnpd.
Read more

Broken, Abandoned, and Forgotten Code, Intermission

We’re about halfway through the Broken, Abandoned series, so this is a good time to pause for a minute and take stock. At this point, things have gotten pretty technical; if you’ve only joined recently, you may be wondering what this series is about. I want to take a moment to summarize where we’ve been and where we can expect to go from here. Overview This series, entitled Broken, Abandoned, and Forgotten Code, is about an unauthenticated firmware update mechanism in the Netgear R6200 wireless router’s UPnP service. Bypassing authentication and updating the firmware would be moderately interesting by itself. What makes this particularly interesting, however, is this capability appears only partially implemented. It’s not quite dead code; more like zombie code. It’s wired up just enough to kind of work. There are many artifacts of incomplete implementation that stand in the way of straightforward exploitation.
Read more

Broken, Abandoned, and Forgotten Code, Part 7

In the previous post, I finished discussing the abCheckBoardID() function. I called attention to a checksum in the header generated by an unknown algorithm. I provided a python implementation of that algorithm ported from IDA disassembly. In total, I identified four fields parsed by this function, accounting for 30 bytes of the 58 byte header. In this part I’ll give an overview of the remaining functions that parse and validate the firmware header. By the end we will be able to generate a header that allows the firmware to be programmed to flash memory. I won’t discuss each header field in quite as much detail as I did previously, but if you’ve made it this far, it shouldn’t be too hard to understand how each field is used.
Read more

Broken, Abandoned, and Forgotten Code, Part 6

Note: It is assumed that the reader is debugging the processes described in this and the next several posts using emulation and IDA Pro. Those topics are outside the scope of this series and are covered in detail here and here. In the previous post, we switched gears and started looking at the web server for the Netgear R6200. That’s because the HTTP daemon’s code for upgrading the firmware is less broken and easier to analyze. We also analyzed a stock firmware image downloaded from Netgear to see how it is composed. Craig Heffner’s binwalk identified three parts, a TRX header at offset 58, followed by a compressed Linux kernel, followed by a squashfs filesystem. All of those parts are well understood, which only leaves the first 58 bytes to analyze.
Read more

Broken, Abandoned, and Forgotten Code, Part 5

In previous installments I shared proof-of-concept code that would exercise the Netgear R6200’s hidden (and badly broken) SetFirmware SOAP action. It satisfied the various wonky conditions necessary to get into the sa_parseRcvCmd() function. Then I showed where in that function a firmware would be decoded from the SOAP request and written to flash. I showed how to identify a code path that leads to firmware writing. In part four, I showed how an undersized malloc() means a stock firmware crashes upnpd. Although we’ll work around that bug later, for this and the next several installments we’ll be working out how the firmware image gets parsed so we can create our own.
Read more

Broken, Abandoned, and Forgotten Code, Part 4

In the last post, I described how upnpd’s sa_parseRcvCmd() function finds the body of a SOAP request and how it parses that SOAP request. This is a large and complicated function that processes many types of SOAP requests. I demonstrated how to work out the desired path of execution to decode and write firmware. At the end I made an educated guess as to how the SOAP request should be formed, and how the firmware should be represented in the request body.
Read more

Broken, Abandoned, and Forgotten Code, Part 3

In the previous posts, I talked about the hidden “SetFirmware” SOAP action in the Netgear R6200’s UPnP daemon, and the weird timing games we have play to deal with UPnP daemon’s broken networking code. I also discussed the haphazard parsing of the HTTP headers across multiple functions. I made a guess at what headers might get our SetFirmware SOAP request passed to the sa_parseRcvCmd() function where hopefully an encapsulated firmware image will be decoded.
Read more

Broken, Abandoned, and Forgotten Code, Part 2

In the part 1, I showed how the Netgear R6200’s upnpd binary contains what appears to be a hidden SOAP action related to the string “SetFirmware”. I also showed how we can get into the upnp_receive_firmware_packets() function if we play timing games and send our request in multiple parts. In this part I’ll describe additional timing considerations needed to avoid hanging the server. I’ll also discuss sloppy parsing of the SOAP request, and I’ll make some guesses as to how that request should be formed.
Read more