Reversing D-Link’s WPS Pin Algorithm

While perusing the latest firmware for D-Link’s DIR-810L 80211ac router, I found an interesting bit of code in sbin/ncc, a binary which provides back-end services used by many other processes on the device, including the HTTP and UPnP servers:

Call to sub_4D56F8 from getWPSPinCode

I first began examining this particular piece of code with the hopes of controlling part of the format string that is passed to __system. However, this data proved not to be user controllable, as the value placed in the format string is the default WPS pin for the router.

The default WPS pin itself is retrieved via a call to sub_4D56F8. Since the WPS pin is typically programmed into NVRAM at the factory, one might expect sub_4D56F8 to simply be performing some NVRAM queries, but that is not the case:

The beginning of sub_4D56F8

This code isn’t retrieving a WPS pin at all, but instead is grabbing the router’s WAN MAC address. The MAC address is then split into its OUI and NIC components, and a tedious set of multiplications, xors, and shifts ensues (full disassembly listing here):

Break out the MAC and start munging the NIC

While the math being performed is not complicated, determining the original programmer’s intent is not necessarily straightforward due to the assembly generated by the compiler. Take the following instruction sequence for example:

li $v0, 0x38E38E39
multu $a3, $v0
...
mfhi $v0
srl $v0, 1

Directly converted into C, this reads:

v0 = ((a3 * 0x38E38E39) >> 32) >> 1;

Which is just a fancy way of dividing by 9:

v0 = a3 / 9;

Likewise, most multiplication and modulus operations are also performed by various sequences of shifts, additions, and subtractions. The multu assembly instruction is only used for the above example where the high 32 bits of a product are needed, and there is nary a divu in sight.

However, after translating the entire sub_4D56F8 disassembly listing into a more palatable format, it’s obvious that this code is using a simple algorithm to generate the default WPS pin entirely from the NIC portion of the device’s WAN MAC address:

But the DIR-810L isn’t the only device to use this algorithm. In fact, it appears to have been in use for some time, dating all the way back to 2007 when WPS was first introduced. The following is an – I’m sure – incomplete list of affected and unaffected devices:

Confirmed Affected:

DIR-810L

DIR-826L

DIR-632

DHP-1320

DIR-835

DIR-615 revs: B2, C1, E1, E3

DIR-657

DIR-827

DIR-857

DIR-451

DIR-655 revs: A3, A4, B1

DIR-825 revs: A1, B1

DIR-651

DIR-855

DIR-628

DGL-4500

DIR-601 revs: A1, B1

DIR-836L

DIR-808L

DIR-636L

DAP-1350

DAP-1555

Confirmed Unaffected:

DIR-815

DIR-505L

DIR-300

DIR-850L

DIR-412

DIR-600

DIR-685

DIR-817LW

DIR-818LW

DIR-803

DIR-845L

DIR-816L

DIR-860L

DIR-645

DIR-685

DAP-1522

Some affected devices, like the DIR-810L, generate the WPS pin from the WAN MAC; most generate it from the BSSID. A stand-alone tool implementing this algorithm can be found here, and has already been rolled into the latest Reaver Pro.

56 Responses to Reversing D-Link’s WPS Pin Algorithm

Great work! So if I understand correctly.. Instead of generating a random PIN at the factory and putting that in NVRAM, they use some code to generate a calculable PIN from the MAC, and put *that* in NVRAM? Whyyyyy? So if you completely wipe NVRAM and then reinstall factory software the number printed on the bottom of the unit is still viable?

Makes you wonder how many other routers have a similar method, since they all need to be able to retrieve that printed PIN on the bottom somehow.

This is why I’ll never buy a consumer router again. I went to pfSense on a dedicated computer and have never looked back.

I was examining the default configs on AT&T U-Verse modem/routers some time ago, and found the device’s serial number is just the decimal version of the unit’s BSSID. The ESSID is ATT### where ### is the last three digits of the serial number–they’re everywhere.

Since the default PSK is a 10-digit decimal number, I suspected it must be derived somehow from the WAN MAC or BSSID. This post has reawakened my curiosity about this. Awesome work Craig.

Search Google and Ebay for people who have taken pictures of the bottoms of their D-Links; there’s usually a sticker on the bottom that shows both the MAC address and the default WPS pin. You can plug the MAC address into the algorithm and see if the same WPS pin pops out. 🙂

Yes, based on that code it appears to be generating a pin from the system’s MAC address (probably the LAN/BSSID MAC). You’ll probably want to verify that against an actual device though.

Are you sure WPS isn’t enabled by default? Just because it has a push button doesn’t mean WPS isn’t open (all WPS enabled routers have a push button); in fact, the push button typically won’t work at all if WPS has been disabled, which is why just about every vendor/ISP leaves WPS enabled by default (user convenience). I’d check the device’s configuration settings and make sure WPS is explicitly disabled.

The pin code matches the last 3 bytes of the mac address on my router (I did not bother to verify the checksum digit though).

Also, WPS is disabled in my setup, and I think it is disabled by default, but I can remember for sure. The web admin interface confirms WPS is off and my wireshark captures as well (the beacon frame shows a MIcrosoft WPS extension if WPS is available).

I also verified that the beacon frames coming from some neighbors at the same ISP do not offer WPS.

I could still be in theory that the router accepts a WPS authentification even though its beacon frames do not advertise for it. This would not be the first security hole this device has to offer. I am quite temptated to try that. That would mean free wifi for me in the whole country ;), let alone all the security/privacy implications this would have.

Router manufacturers REALLY need to subject their firmware developers to third-party code reviews. Or even code reviews. Heck, things would be loads better if they just assigned a QA person to test around their code. The context here is security, but there’s other context to worry about like network abuse.

Good luck trying to notify D-Link security officers about this; you’ll have to talk your way past Mumbai support first.

I worked on a DDNS provider’s update server for many years. A majority of the DDNS abuse traffic came from D-Link. Far more than from Linksys, etc. D-Link developers would allow end users to “enable” DDNS, and then SAVE even if domain, username and password were blank. They would also automatically retry failed credentials forever, as if the server might somehow get exhausted and accept bad credentials. You could try to block D-link’s user Agent, but then they would do things like put random text into the Agent String to escape blocking. There was also some incident years ago where D-Link firmware would DDOS public NTP servers.

These people are clearly not network enthusiasts. If you want to pick out their faults, your blog will be busy for a long time…