WPS Scan


SUBMITTED BY: Guest

DATE: Dec. 5, 2013, 2:46 p.m.

FORMAT: Python

SIZE: 10.3 kB

HITS: 754

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

comments powered by Disqus