Reversing Belkin’s WPS Pin Algorithm

After finding D-Link’s WPS algorithm, I was curious to see which vendors might have similar algorithms, so I grabbed some Belkin firmware and started dissecting it. This particular firmware uses the SuperTask! RTOS, and in fact uses the same firmware obfuscation as seen previously on the Linksys WRT120N:

Being a known obfuscation method, binwalk was able to de-obfuscate and extract the compressed firmware image. The next step was to figure out the code’s load address in order to get a proper disassembly in IDA; if the code is disassembled with the wrong load address, absolute memory references won’t be properly resolved.

Absolute addresses in the code can hint at the load address, such as this loop which zeros out the BSS data section:

BSS zero loop

BSS zeroing loops are usually easy to spot, as they will zero out relatively large regions of memory, and are typically encountered very early on in the code.

Here, the code is filling everything from 0x802655F0 to 0x80695574 with zeros, so this must be a valid address range in memory. Further, BSS is commonly located just after all the other code and data sections; in this case, the firmware image we’ve loaded into IDA is 0x2635EB bytes in size, so we would expect the BSS section to begin somewhere after this in memory:

End of ROM

In fact, subtracting the size of the firmware image from the start of the BSS section results in a value suspiciously close to 0x800002000:

0x802655F0 - 0x2635EB = 0x800002005

Setting 0x800002000 as the load address in IDA, we get a rather respectable disassembly:

A reasonable disassembly listing

With a reasonable disassembly, searching for a WPS pin generation algorithm could begin in ernest. When looking for functions related to generating WPS pins, it’s reasonable to assume that they’ll have to, at some point, calculate the WPS pin checksum. It would be useful to begin the search by first identifying the function(s) responsible for calculating the WPS pin checksum.

However, without a symbol table, finding a function conveniently named “wps_checksum” is not likely; luckily, MIPS C compilers tend to generate a predictable set of immediate values when generating the WPS checksum assembly code, a pattern I noticed when reversing D-Link’s WPS pin algorithm. Using an IDAPython script to search for these immediate values greatly simplifies the process of identifying the WPS checksum function:

WPS pin checksum immediate values

There are only a few functions that call wps_checksum, and one of them contains a reference to a very interesting string:

“GenerateDefaultPin”

There’s a lot of xoring and shifting going on in the GenerateDefaultPin code, but what is more interesting is what data it is munging. Looking at the values passed to GenerateDefaultPin, we can see that it is given both the router’s MAC address and serial number:

GenerateDefaultPin(char *buf, int unused, char *mac, char *serial);

MAC addresses are easily gathered by a wireless attacker; serial numbers can be a bit more difficult. Although serial numbers aren’t particularly random, GenerateDefaultPin uses the least significant 4 digits of the serial number, which are unpredictable enough to prevent an external attacker from reliably calculating the WPS pin.

Or, at least that would be the case if the Belkin’s 802.11 probe response packets didn’t include the device’s serial number in its WPS information element:

Belkin probe response packet, captured in Wireshark

Since WiFi probe request/response packets are not encrypted, an attacker can gather the MAC address (the MAC address used by the algorithm is the LAN MAC) and serial number of a target by sending a single probe request packet to a victim access point.

We just need to reverse the GenerateDefaultPin code to determine how it is using the MAC address and serial number to create a unique WPS pin (download PoC here):

Of the 24 Belkin routers tested, 80% of them were found to be using this algorithm for their default WPS pin:

Confirmed vulnerable:

F9K1001v4

F9K1001v5

F9K1002v1

F9K1002v2

F9K1002v5

F9K1103v1

F9K1112v1

F9K1113v1

F9K1105v1

F6D4230-4v2

F6D4230-4v3

F7D2301v1

F7D1301v1

F5D7234-4v3

F5D7234-4v4

F5D7234-4v5

F5D8233-4v1

F5D8233-4v3

F5D9231-4v1

Confirmed not vulnerable:

F9K1001v1

F9K1105v2

F6D4230-4v1

F5D9231-4v2

F5D8233-4v4

It’s not entirely fair to pick on Belkin though, as this appears to be an issue specific to Arcadyan, who is the ODM for many Belkin products, as well as others. This means that there are additional devices and vendors affected besides those listed above.

You could do it, but that would require an active attack and would essentially be no different than using reaver (typically takes 10 hours or so, assuming the vendor didn’t implement brute force mitigations).

In a wps attack using the pin gen what information is given about the network card creating the attack? For instance the “sending identity response” function. Does this send equivalent s/n and mac address information that is received in response from the attacked router?