Blog

Belkin F9K1111 V1.04.10 Firmware Analysis

Posted by Vectra Threat Labs on Aug 18, 2015 5:02:00 PM

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 [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.

unpacked_update

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.

Board_Annotated

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.

mxic

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.

spidumpstuff

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 <outfile> to obtain the contents of the chip.

$ python goodfet.spiflash dump s

dumping

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).

verification

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.

winmerge

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 formHwSet in 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:

removed

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.formusbstorage

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 action formWlanMP.  Tracing the calls to websGetVar, we see a few possibilities.

formwlanmp11

Following forwared, we see that these few possibilities will all work as avenues for injection into the system call -- we chose ateFunc.

formwlanmp1

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.

formHwSet11

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.

formConnectionSetting11

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:

formbsssitesurvey1

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.  

bss1

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:

escaped

This (presumably correctly) escaped string is then passed as normal to system via sprintf as before.

bss2

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.

[1] http://cache-www.belkin.com/support/dl/F9K1111_WW_1.04.10_upg.bin

[2] http://binwalk.org

[3] http://goodfet.sourceforge.net/apps/spi

[4] http://winmerge.org

Subscribe to the Vectra Blog



Recent Posts

Posts by Topic

Follow us