Introduction
Recently, it came to our attention that HP DVLabs has uncovered at least ten vulnerabilities in the Belkin N300 Dual-Band Wi-Fi Range Extender (F9K1111). In response to this, Belkin released firmware version 1.04.10. As this is the first update issued for the F9K1111 and there were not any public triggers for the vulnerabilities, we thought it would be interesting to take a deeper look.
Unpacking the update
To begin our analysis, we downloaded the firmware update from the vendor. We used a firmware tool called binwalk to unpack the update:
$ binwalk -Me F9K1111_WW_1.04.10_upg.bin
Our result is a pretty standard looking extracted SquashFS filesystem representing the root of the device as seen below.
Now in order to perform the bindiff, we will need to interact with the hardware a bit to get the files in their pre-patched state.
Getting the base firmware
To analyze the base firmware, we will need some way to dump the data off the physical device. To do this, we must first remove the device from its casing.
Highlighted in red and blue are possible avenues for retrieving the firmware, the SPI flash chip and the UART interface respectively. Although we have seen some level of activity on the UART, we will proceed by analyzing the base image on the SPI flash chip. The pinout for the chip we are dealing with, MX25L1606e, is readily available from Macronix.
After grabbing this sheet and removing the chip, we are ready to wire up up our GoodFET with respect to the above generic 8-pin pinout.
After bridging pins 7 and 8, we verify that everything is hooked up correctly with
$ python goodfet.spiflash info
Next we can run goodfet.spiflash dump to obtain the contents of the chip.
$ python goodfet.spiflash dump s
Finally, we can do a quick strings on the resulting file to ensure that the dump looks legit (ie contains at least some readable strings).
The resulting binary file can be unpacked nicely via binwalk as before.
Diffing the update
Moving both unpacked filesystems over to a Windows box and dropping them into WinMerge, we can see that really not much has changed.
The files compiler_data, version, and FUNCTION_SCRIPT do not contain any interesting changes (apart from perhaps for some data which might be useful for fingerprinting). The change to util_system.asp is not too interesting either. So, pretty much we will be looking at Belkin's modifications to webs, the GoAhead Webserver.
Analysis of webs
HP's Zero Day Initiative has named the vulnerabilities with what appear to be affected function names or inputs. They are as follows:
- formWpsStart pinCode Remote CodeExecution Vulnerability
- formWlanSetupWPS wps_enrolee_pin Remote Code Execution Vulnerability
- formWlanMP Remote Code Execution Vulnerability
- formBSSetSitesurvey Remote Code Execution Vulnerability
- formHwSet Remote Code Execution Vulnerability
- formConnectionSetting Remote Code Execution Vulnerability
- formAccept Remote Code Execution Vulnerability
- formiNICWpsStart Remote Code Execution Vulnerability
- formUSBStorage Remote Code Execution Vulnerability
So, after loading the patched version of webs into IDA, we searched for formHwSetin the list of functions and found nothing. In fact many of these functions weren't found. Pulling up Bindiff, we can see that 7 functions were removed during the update:
These correspond well to the data from the ZDI bulletin. In fact, every function listed in the ZDI advisories has been removed except for formWlanSetupWPS and formBSSetSitesurvey. Let's take some time to look at the removed functions.
formUsbStorage
The first function we consider is formUsbStorage. After giving the function a quick read, it is pretty obvious what the problem is here. The POST variable sub_dir which is accessed via the GoAhead webs API function websGetVar is then being used in a call to system, allowing for command injection.
This code could be triggered via:
wget --post-data="sub_dir=vectra;reboot" http://belkin.range/goform/formUSBStorage
formWlanMP
A similar error can be found in form actionformWlanMP. Tracing the calls to websGetVar, we see a few possibilities.
Following forwared, we see that these few possibilities will all work as avenues for injection into the system call -- we chose ateFunc.
This code could be triggered via:
wget --post-data="ateFunc=;reboot;" http://belkin.range/goform/formWlanMP
formHwSet
There is more command injection here, this time we are using the variable [sic] Anntena.
This code could be triggered via:
wget --post-data="Anntena=;reboot;" http://belkin.range/goform/formHwSet
formConnectionSetting
Here, we've got command injection in the timeOut parameter in the formConnectionSetting function.
This code could be triggered via:
wget --post-data="timeOut=1;reboot;" http://belkin.range/goform/formConnectionSetting
formBSSetSitesurvey
At this point, we've beaten the deleted function horse to death. Let's take a look at the more significant of the functions that Belkin decided not to delete - formBSSetSitesurvey. Here is an overview:
After recoiling in horror, we can zoom in and see that the major change is that Belkin has added a function called strcat_escape which is used throughout this function on sources originating form websGetVar.
This strcat_escape function takes 3 buffers - dst, src, and tokens. The function uses nested loops to search the src string for existence of any of the tokens to be escaped, if found they are escaped before being copied into dst. In the pictured case token_of_none_quotation is passed as tokens which is defined as"\\\"'$()<>` #&*
We reimplemented this function in C from the webs binary and can see expected output:
This (presumably correctly) escaped string is then passed as normal to system via sprintf as before.
The effectiveness of this patch relies on a few factors:
- strcat_escape function works completely as intended
- strcat_escape does not unintentionally cause buffer overflows ;-)
- strcat_escape is used on all user input which ends up at system
- We have been in contact with Belkin about a few of these bullet points.
Conclusion
We are all already aware that the security maturity embedded device code is a problem. Here we see that even in devices released in 2014, it remains a problem.