SOHO Device Exploitation
After a long day of hard research, it’s fun to relax, kick back, and do something easy. While modern software development processes have vastly improved the quality of commercial software as compared to 10-15 years ago, consumer network devices have largely been left behind. Thus, when it’s time for some quick fun and a nice confidence boost, I like to analyze Small Office/Home Office (SOHO) devices. This blog describes one such session of auditing the Netgear R7000 router, analyzing the resulting vulnerability, and the exploit development process that followed. The write-up and code for the vulnerability described in this blog post can be found in our NotQuite0DayFriday repository.
The first step when analyzing a SOHO device is to obtain the firmware. Thankfully, Netgear’s support website hosts all of the firmwares for the R7000. The Netgear R7000 version 184.108.40.206 firmware used in this blog post can be downloaded from this website. After unzipping the firmware, we’ll use binwalk to extract the root filesystem from the firmware image:
While the router may have many services worth analyzing, the web server is often the most likely to contain vulnerabilities. In SOHO devices like the R7000, the web server must parse user input from the network and run complex CGI functions that use that input. Furthermore, the web server is written in C and has had very little testing, and thus it is often vulnerable to trivial memory corruption bugs. As such, I decided to start by analyzing the web server, httpd.
As we’re interested in how the web server (mis)handles user input, the logical place to begin analyzing the web server is the recv function. The recv function is used to retrieve the user input from a connection. Thus by looking at the references to the recv function in the web server, we can see where the user input begins. The web server has two helper functions which call recv, one used in the http parser and one used to read the responses from Dynamic DNS requests to oemdns.com. We’ll focus on the former use, as shown below in the Hex-Rays decompiler:
After the call to read_content (the recv helper function), the parser does some error checking, combines the received content with any previously received content, and then looks for the strings name="mtenFWUpload" and "\r\n\r\n" in the user input. If the user input contains these strings, the rest of the user input after these strings is passed to the abCheckBoardID function. Grepping the firmware’s root file system, we can see that the string mtenFWUpload is referenced from the files www/UPG_upgrade.htm and www/Modem_upgrade.htm, and thus we can conclude that this is part of the router’s upgrade functionality.
1996 Called, They Want Their Vulnerability Back
Following the user input, we’ll next look at the abCheckBoardID function. This function, shown below, expects the user input to be the chk firmware file for the R7000. It parses the user input to validate the magic value (bytes 0-3), obtains the header size (bytes 4-7) and checksum (bytes 36-49), and then copies the header to a stack buffer. This copy, performed via the memcpy function, uses the size specified in the user input. As such, it’s trivial to overflow the stack buffer.
In most modern software, this vulnerability would be unexploitable. Modern software typically contains stack cookies which would prevent exploitation. However, the R7000 does not use stack cookies. In fact, of all of the Netgear products which share a common codebase, only the D8500 firmware version 220.127.116.11 and the R6300v2 firmware versions 18.104.22.168-22.214.171.124 use stack cookies. However, later versions of the D8500 and R6300v2 stopped using stack cookies, making this vulnerability once again exploitable. This is just one more example of how SOHO device security has fallen behind as compared to other modern software.
In addition to lacking stack cookies, the web server is also not compiled as a Position-independent Executable (PIE), and thus cannot take full advantage of ASLR. As such, it’s trivial to find a ROP gadget within the httpd binary, such as the one shown below, that will call system with a command taken from the overflown stack.
The exploit in GRIMM’s NotQuite0DayFriday repository uses this gadget to start the telnet daemon as root listening on TCP port 8888 and not requiring a password to login.
As the vulnerability occurs before the Cross-Site Request Forgery (CSRF) token is checked, this exploit can also be served via a CSRF attack. If a user with a vulnerable router browses to a malicious website, that website could exploit the user’s router. The developed exploit demonstrates this ability by serving an html page which sends an AJAX request containing the exploit to the target device. However, as the CSRF web page cannot read any responses from the target server, it is not possible to remotely fingerprint the device. Rather, the attacker must know the model and version that they are exploiting, as shown below.
Automating the Process
A lot of SOHO devices share a common software base, especially among devices created by the same manufacturer. As such, a vulnerability in one device can normally be found in similar devices by the same manufacturer. In this particular case, I was able to identify 79 different Netgear devices and 758 firmware images that included a vulnerable copy of the web server. This vulnerability affects firmwares as early as 2007 (WGT624v4, version 2.0.6). Given the large number of firmware images, manually finding the appropriate gadgets is infeasible. Rather, this is a good opportunity to automate gadget detection.
Included in GRIMM’s NotQuite0DayFriday repository is the find_arm_gadget.sh and find_mips_gadget.sh shell scripts. The find_arm_gadget.sh shell script uses objdump and grep to look for the needed gadget, as shown below. While the R7000 has an ARM processor, some of the other vulnerable devices use a MIPS processor. Unlike ARM, objdump cannot easily resolve the function names of functions being called in a MIPS binary. As such, the MIPS gadget identification scripts use IDAPython in order to identify the gadgets for a binary. Using these sets of scripts, I was able to create an exploit for each of the 758 vulnerable firmware images. Afterwards, I manually tested the exploit on 28 of the vulnerable devices to ensure that the identified gadgets worked as expected.
The last step before exploitation can reliably be achieved is to remotely detect the model and version of the router. Thankfully, almost all of the vulnerable versions listen for requests to the URL /currentsetting.htm and return the model and version of the device. As such, remotely fingerprinting a device is trivial. The published exploit for the vulnerability described in this blog post automatically determines the target model and version using this approach.
Routers and modems often form an important security border that prevents attackers from directly exploiting the computers in a network. However, poor code quality and a lack of adequate testing has resulted in thousands of vulnerable SOHO devices being exposed to the internet for over a decade. This blog post illustrates just how far behind the times consumer network device security has fallen.
On 6/15/2020, ZDI published an advisory by d4rkn3ss from VNPT ISC on this vulnerability. We discovered the issue independently and reported the vulnerability directly to Netgear on 5/7/2020. ZDI's advisory can be read at https://www.zerodayinitiative.com/advisories/ZDI-20-712/
Want to join us and exploit some binaries? We’re hiring. Need help auditing or exploiting your binaries? Feel free to contact us.