1## This file is part of Scapy 2## See http://www.secdev.org/projects/scapy for more informations 3## Copyright (C) Philippe Biondi <phil@secdev.org> 4## This program is published under a GPLv2 license 5 6""" 7Wireless LAN according to IEEE 802.11. 8""" 9 10from __future__ import print_function 11import re,struct 12from zlib import crc32 13 14from scapy.config import conf, crypto_validator 15from scapy.data import * 16from scapy.compat import * 17from scapy.packet import * 18from scapy.fields import * 19from scapy.ansmachine import * 20from scapy.plist import PacketList 21from scapy.layers.l2 import * 22from scapy.layers.inet import IP, TCP 23from scapy.error import warning 24 25 26if conf.crypto_valid: 27 from cryptography.hazmat.backends import default_backend 28 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms 29else: 30 default_backend = Ciphers = algorithms = None 31 log_loading.info("Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption.") 32 33 34### Layers 35 36 37class PrismHeader(Packet): 38 """ iwpriv wlan0 monitor 3 """ 39 name = "Prism header" 40 fields_desc = [ LEIntField("msgcode",68), 41 LEIntField("len",144), 42 StrFixedLenField("dev","",16), 43 LEIntField("hosttime_did",0), 44 LEShortField("hosttime_status",0), 45 LEShortField("hosttime_len",0), 46 LEIntField("hosttime",0), 47 LEIntField("mactime_did",0), 48 LEShortField("mactime_status",0), 49 LEShortField("mactime_len",0), 50 LEIntField("mactime",0), 51 LEIntField("channel_did",0), 52 LEShortField("channel_status",0), 53 LEShortField("channel_len",0), 54 LEIntField("channel",0), 55 LEIntField("rssi_did",0), 56 LEShortField("rssi_status",0), 57 LEShortField("rssi_len",0), 58 LEIntField("rssi",0), 59 LEIntField("sq_did",0), 60 LEShortField("sq_status",0), 61 LEShortField("sq_len",0), 62 LEIntField("sq",0), 63 LEIntField("signal_did",0), 64 LEShortField("signal_status",0), 65 LEShortField("signal_len",0), 66 LESignedIntField("signal",0), 67 LEIntField("noise_did",0), 68 LEShortField("noise_status",0), 69 LEShortField("noise_len",0), 70 LEIntField("noise",0), 71 LEIntField("rate_did",0), 72 LEShortField("rate_status",0), 73 LEShortField("rate_len",0), 74 LEIntField("rate",0), 75 LEIntField("istx_did",0), 76 LEShortField("istx_status",0), 77 LEShortField("istx_len",0), 78 LEIntField("istx",0), 79 LEIntField("frmlen_did",0), 80 LEShortField("frmlen_status",0), 81 LEShortField("frmlen_len",0), 82 LEIntField("frmlen",0), 83 ] 84 def answers(self, other): 85 if isinstance(other, PrismHeader): 86 return self.payload.answers(other.payload) 87 else: 88 return self.payload.answers(other) 89 90class RadioTap(Packet): 91 name = "RadioTap dummy" 92 fields_desc = [ ByteField('version', 0), 93 ByteField('pad', 0), 94 FieldLenField('len', None, 'notdecoded', '<H', adjust=lambda pkt,x:x+8), 95 FlagsField('present', None, -32, ['TSFT','Flags','Rate','Channel','FHSS','dBm_AntSignal', 96 'dBm_AntNoise','Lock_Quality','TX_Attenuation','dB_TX_Attenuation', 97 'dBm_TX_Power', 'Antenna', 'dB_AntSignal', 'dB_AntNoise', 98 'b14', 'b15','b16','b17','b18','b19','b20','b21','b22','b23', 99 'b24','b25','b26','b27','b28','b29','b30','Ext']), 100 StrLenField('notdecoded', "", length_from= lambda pkt:pkt.len-8) ] 101 102class PPI(Packet): 103 name = "Per-Packet Information header (partial)" 104 fields_desc = [ ByteField("version", 0), 105 ByteField("flags", 0), 106 FieldLenField("len", None, fmt="<H", length_of="notdecoded", adjust=lambda pkt,x:x+8), 107 LEIntField("dlt", 0), 108 StrLenField("notdecoded", "", length_from = lambda pkt:pkt.len-8) 109 ] 110 111 112class Dot11(Packet): 113 name = "802.11" 114 fields_desc = [ 115 BitField("subtype", 0, 4), 116 BitEnumField("type", 0, 2, ["Management", "Control", "Data", 117 "Reserved"]), 118 BitField("proto", 0, 2), 119 FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", 120 "pw-mgt", "MD", "wep", "order"]), 121 ShortField("ID",0), 122 MACField("addr1", ETHER_ANY), 123 ConditionalField( 124 MACField("addr2", ETHER_ANY), 125 lambda pkt: (pkt.type != 1 or 126 pkt.subtype in [0x9, 0xb, 0xa, 0xe, 0xf]), 127 ), 128 ConditionalField( 129 MACField("addr3", ETHER_ANY), 130 lambda pkt: pkt.type in [0, 2], 131 ), 132 ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type != 1), 133 ConditionalField( 134 MACField("addr4", ETHER_ANY), 135 lambda pkt: (pkt.type == 2 and 136 pkt.FCfield & 3 == 3), ## from-DS+to-DS 137 ), 138 ] 139 def mysummary(self): 140 return self.sprintf("802.11 %Dot11.type% %Dot11.subtype% %Dot11.addr2% > %Dot11.addr1%") 141 def guess_payload_class(self, payload): 142 if self.type == 0x02 and (0x08 <= self.subtype <= 0xF and self.subtype != 0xD): 143 return Dot11QoS 144 elif self.FCfield & 0x40: 145 return Dot11WEP 146 else: 147 return Packet.guess_payload_class(self, payload) 148 def answers(self, other): 149 if isinstance(other,Dot11): 150 if self.type == 0: # management 151 if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA 152 return 0 153 if (other.subtype,self.subtype) in [(0,1),(2,3),(4,5)]: 154 return 1 155 if self.subtype == other.subtype == 11: # auth 156 return self.payload.answers(other.payload) 157 elif self.type == 1: # control 158 return 0 159 elif self.type == 2: # data 160 return self.payload.answers(other.payload) 161 elif self.type == 3: # reserved 162 return 0 163 return 0 164 def unwep(self, key=None, warn=1): 165 if self.FCfield & 0x40 == 0: 166 if warn: 167 warning("No WEP to remove") 168 return 169 if isinstance(self.payload.payload, NoPayload): 170 if key or conf.wepkey: 171 self.payload.decrypt(key) 172 if isinstance(self.payload.payload, NoPayload): 173 if warn: 174 warning("Dot11 can't be decrypted. Check conf.wepkey.") 175 return 176 self.FCfield &= ~0x40 177 self.payload=self.payload.payload 178 179 180class Dot11QoS(Packet): 181 name = "802.11 QoS" 182 fields_desc = [ BitField("Reserved",None,1), 183 BitField("Ack Policy",None,2), 184 BitField("EOSP",None,1), 185 BitField("TID",None,4), 186 ByteField("TXOP",None) ] 187 def guess_payload_class(self, payload): 188 if isinstance(self.underlayer, Dot11): 189 if self.underlayer.FCfield & 0x40: 190 return Dot11WEP 191 return Packet.guess_payload_class(self, payload) 192 193 194capability_list = [ "res8", "res9", "short-slot", "res11", 195 "res12", "DSSS-OFDM", "res14", "res15", 196 "ESS", "IBSS", "CFP", "CFP-req", 197 "privacy", "short-preamble", "PBCC", "agility"] 198 199reason_code = {0:"reserved",1:"unspec", 2:"auth-expired", 200 3:"deauth-ST-leaving", 201 4:"inactivity", 5:"AP-full", 6:"class2-from-nonauth", 202 7:"class3-from-nonass", 8:"disas-ST-leaving", 203 9:"ST-not-auth"} 204 205status_code = {0:"success", 1:"failure", 10:"cannot-support-all-cap", 206 11:"inexist-asso", 12:"asso-denied", 13:"algo-unsupported", 207 14:"bad-seq-num", 15:"challenge-failure", 208 16:"timeout", 17:"AP-full",18:"rate-unsupported" } 209 210class Dot11Beacon(Packet): 211 name = "802.11 Beacon" 212 fields_desc = [ LELongField("timestamp", 0), 213 LEShortField("beacon_interval", 0x0064), 214 FlagsField("cap", 0, 16, capability_list) ] 215 216 217class Dot11Elt(Packet): 218 name = "802.11 Information Element" 219 fields_desc = [ ByteEnumField("ID", 0, {0:"SSID", 1:"Rates", 2: "FHset", 3:"DSset", 4:"CFset", 5:"TIM", 6:"IBSSset", 16:"challenge", 220 42:"ERPinfo", 46:"QoS Capability", 47:"ERPinfo", 48:"RSNinfo", 50:"ESRates",221:"vendor",68:"reserved"}), 221 FieldLenField("len", None, "info", "B"), 222 StrLenField("info", "", length_from=lambda x:x.len) ] 223 def mysummary(self): 224 if self.ID == 0: 225 ssid = repr(self.info) 226 if ssid[:2] in ['b"', "b'"]: 227 ssid = ssid[1:] 228 return "SSID=%s" % ssid, [Dot11] 229 else: 230 return "" 231 232class Dot11ATIM(Packet): 233 name = "802.11 ATIM" 234 235class Dot11Disas(Packet): 236 name = "802.11 Disassociation" 237 fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] 238 239class Dot11AssoReq(Packet): 240 name = "802.11 Association Request" 241 fields_desc = [ FlagsField("cap", 0, 16, capability_list), 242 LEShortField("listen_interval", 0x00c8) ] 243 244 245class Dot11AssoResp(Packet): 246 name = "802.11 Association Response" 247 fields_desc = [ FlagsField("cap", 0, 16, capability_list), 248 LEShortField("status", 0), 249 LEShortField("AID", 0) ] 250 251class Dot11ReassoReq(Packet): 252 name = "802.11 Reassociation Request" 253 fields_desc = [ FlagsField("cap", 0, 16, capability_list), 254 LEShortField("listen_interval", 0x00c8), 255 MACField("current_AP", ETHER_ANY) ] 256 257 258class Dot11ReassoResp(Dot11AssoResp): 259 name = "802.11 Reassociation Response" 260 261class Dot11ProbeReq(Packet): 262 name = "802.11 Probe Request" 263 264class Dot11ProbeResp(Packet): 265 name = "802.11 Probe Response" 266 fields_desc = [ LELongField("timestamp", 0), 267 LEShortField("beacon_interval", 0x0064), 268 FlagsField("cap", 0, 16, capability_list) ] 269 270class Dot11Auth(Packet): 271 name = "802.11 Authentication" 272 fields_desc = [ LEShortEnumField("algo", 0, ["open", "sharedkey"]), 273 LEShortField("seqnum", 0), 274 LEShortEnumField("status", 0, status_code) ] 275 def answers(self, other): 276 if self.seqnum == other.seqnum+1: 277 return 1 278 return 0 279 280class Dot11Deauth(Packet): 281 name = "802.11 Deauthentication" 282 fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] 283 284 285 286class Dot11WEP(Packet): 287 name = "802.11 WEP packet" 288 fields_desc = [ StrFixedLenField("iv", b"\0\0\0", 3), 289 ByteField("keyid", 0), 290 StrField("wepdata",None,remain=4), 291 IntField("icv",None) ] 292 293 @crypto_validator 294 def decrypt(self, key=None): 295 if key is None: 296 key = conf.wepkey 297 if key: 298 d = Cipher( 299 algorithms.ARC4(self.iv + key.encode("utf8")), 300 None, 301 default_backend(), 302 ).decryptor() 303 self.add_payload(LLC(d.update(self.wepdata) + d.finalize())) 304 305 def post_dissect(self, s): 306 self.decrypt() 307 308 def build_payload(self): 309 if self.wepdata is None: 310 return Packet.build_payload(self) 311 return b"" 312 313 @crypto_validator 314 def encrypt(self, p, pay, key=None): 315 if key is None: 316 key = conf.wepkey 317 if key: 318 if self.icv is None: 319 pay += struct.pack("<I", crc32(pay) & 0xffffffff) 320 icv = b"" 321 else: 322 icv = p[4:8] 323 e = Cipher( 324 algorithms.ARC4(self.iv + key.encode("utf8")), 325 None, 326 default_backend(), 327 ).encryptor() 328 return p[:4] + e.update(pay) + e.finalize() + icv 329 else: 330 warning("No WEP key set (conf.wepkey).. strange results expected..") 331 return b"" 332 333 def post_build(self, p, pay): 334 if self.wepdata is None: 335 p = self.encrypt(p, raw(pay)) 336 return p 337 338 339class Dot11Ack(Packet): 340 name = "802.11 Ack packet" 341 342 343bind_layers( PrismHeader, Dot11, ) 344bind_layers( RadioTap, Dot11, ) 345bind_layers( PPI, Dot11, dlt=105) 346bind_layers( Dot11, LLC, type=2) 347bind_layers( Dot11QoS, LLC, ) 348bind_layers( Dot11, Dot11AssoReq, subtype=0, type=0) 349bind_layers( Dot11, Dot11AssoResp, subtype=1, type=0) 350bind_layers( Dot11, Dot11ReassoReq, subtype=2, type=0) 351bind_layers( Dot11, Dot11ReassoResp, subtype=3, type=0) 352bind_layers( Dot11, Dot11ProbeReq, subtype=4, type=0) 353bind_layers( Dot11, Dot11ProbeResp, subtype=5, type=0) 354bind_layers( Dot11, Dot11Beacon, subtype=8, type=0) 355bind_layers( Dot11, Dot11ATIM, subtype=9, type=0) 356bind_layers( Dot11, Dot11Disas, subtype=10, type=0) 357bind_layers( Dot11, Dot11Auth, subtype=11, type=0) 358bind_layers( Dot11, Dot11Deauth, subtype=12, type=0) 359bind_layers( Dot11, Dot11Ack, subtype=13, type=1) 360bind_layers( Dot11Beacon, Dot11Elt, ) 361bind_layers( Dot11AssoReq, Dot11Elt, ) 362bind_layers( Dot11AssoResp, Dot11Elt, ) 363bind_layers( Dot11ReassoReq, Dot11Elt, ) 364bind_layers( Dot11ReassoResp, Dot11Elt, ) 365bind_layers( Dot11ProbeReq, Dot11Elt, ) 366bind_layers( Dot11ProbeResp, Dot11Elt, ) 367bind_layers( Dot11Auth, Dot11Elt, ) 368bind_layers( Dot11Elt, Dot11Elt, ) 369 370 371conf.l2types.register(DLT_IEEE802_11, Dot11) 372conf.l2types.register_num2layer(801, Dot11) 373conf.l2types.register(DLT_PRISM_HEADER, PrismHeader) 374conf.l2types.register_num2layer(802, PrismHeader) 375conf.l2types.register(DLT_IEEE802_11_RADIO, RadioTap) 376conf.l2types.register_num2layer(803, RadioTap) 377conf.l2types.register(DLT_PPI, PPI) 378 379 380class WiFi_am(AnsweringMachine): 381 """Before using this, initialize "iffrom" and "ifto" interfaces: 382iwconfig iffrom mode monitor 383iwpriv orig_ifto hostapd 1 384ifconfig ifto up 385note: if ifto=wlan0ap then orig_ifto=wlan0 386note: ifto and iffrom must be set on the same channel 387ex: 388ifconfig eth1 up 389iwconfig eth1 mode monitor 390iwconfig eth1 channel 11 391iwpriv wlan0 hostapd 1 392ifconfig wlan0ap up 393iwconfig wlan0 channel 11 394iwconfig wlan0 essid dontexist 395iwconfig wlan0 mode managed 396""" 397 function_name = "airpwn" 398 filter = None 399 400 def parse_options(self, iffrom=conf.iface, ifto=conf.iface, replace="", 401 pattern="", ignorepattern=""): 402 self.iffrom = iffrom 403 self.ifto = ifto 404 self.ptrn = re.compile(pattern.encode()) 405 self.iptrn = re.compile(ignorepattern.encode()) 406 self.replace = replace 407 408 def is_request(self, pkt): 409 if not isinstance(pkt,Dot11): 410 return 0 411 if not pkt.FCfield & 1: 412 return 0 413 if not pkt.haslayer(TCP): 414 return 0 415 ip = pkt.getlayer(IP) 416 tcp = pkt.getlayer(TCP) 417 pay = raw(tcp.payload) 418 if not self.ptrn.match(pay): 419 return 0 420 if self.iptrn.match(pay) == True: 421 return 0 422 return True 423 424 def make_reply(self, p): 425 ip = p.getlayer(IP) 426 tcp = p.getlayer(TCP) 427 pay = raw(tcp.payload) 428 del(p.payload.payload.payload) 429 p.FCfield="from-DS" 430 p.addr1,p.addr2 = p.addr2,p.addr1 431 p /= IP(src=ip.dst,dst=ip.src) 432 p /= TCP(sport=tcp.dport, dport=tcp.sport, 433 seq=tcp.ack, ack=tcp.seq+len(pay), 434 flags="PA") 435 q = p.copy() 436 p /= self.replace 437 q.ID += 1 438 q.getlayer(TCP).flags="RA" 439 q.getlayer(TCP).seq+=len(self.replace) 440 return [p,q] 441 442 def print_reply(self, query, *reply): 443 p = reply[0][0] 444 print(p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%")) 445 446 def send_reply(self, reply): 447 sendp(reply, iface=self.ifto, **self.optsend) 448 449 def sniff(self): 450 sniff(iface=self.iffrom, **self.optsniff) 451 452 453conf.stats_dot11_protocols += [Dot11WEP, Dot11Beacon, ] 454 455 456 457 458 459class Dot11PacketList(PacketList): 460 def __init__(self, res=None, name="Dot11List", stats=None): 461 if stats is None: 462 stats = conf.stats_dot11_protocols 463 464 PacketList.__init__(self, res, name, stats) 465 def toEthernet(self): 466 data = [x[Dot11] for x in self.res if Dot11 in x and x.type == 2] 467 r2 = [] 468 for p in data: 469 q = p.copy() 470 q.unwep() 471 r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP 472 return PacketList(r2,name="Ether from %s"%self.listname) 473 474 475