Belkin F9K1111 V1.04.10 Firmware Analysis

Belkin F9K1111 V1.04.10 Firmware Analysis

Vectra Threat Labs
August 19, 2015


Recently, it came to our attention that HP DVLabs has uncovered at least tenvulnerabilitiesin 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 [1]. We used a firmware tool called binwalk [2]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, wemust 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 [3]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 [4], we can see that really not much has changed.

The files compiler_data, version, and FUNCTION_SCRIPTdo not contain any interesting changes (apart from perhaps for some data which might be useful for fingerprinting). The change to util_system.aspis 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 Initiativehas 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.


The first function we consider isformUsbStorage. After giving the function a quick read, it is pretty obvious what the problem is here. The POST variablesub_dirwhich is accessed via the GoAhead webs API function websGetVar is then being used in a call tosystem, allowing for command injection.

This code could be triggered via:

wget --post-data="sub_dir=vectra;reboot" http://belkin.range/goform/formUSBStorage


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


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


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


At this point, we've beaten the deleted function horse to death. Let's take a look at the more significantof the functions that Belkin decided not to delete - formBSSetSitesurvey. Here is an overview:

After recoilingin 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 existenceof any of the tokens to be escaped, if found they are escaped before being copied into dst. In the pictured casetoken_of_none_quotation is passed as tokenswhich is defined as"\\\"'$()<>` #&*