1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7Wireless LAN according to IEEE 802.11.
8
9This file contains bindings for 802.11 layers and some usual linklayers:
10 - PRISM
11 - RadioTap
12"""
13
14import re
15import struct
16from zlib import crc32
17
18from scapy.config import conf, crypto_validator
19from scapy.data import ETHER_ANY, DLT_IEEE802_11, DLT_PRISM_HEADER, \
20 DLT_IEEE802_11_RADIO
21from scapy.compat import raw, plain_str, orb, chb
22from scapy.packet import Packet, bind_layers, bind_top_down, NoPayload
23from scapy.fields import (
24 BitEnumField,
25 BitField,
26 BitMultiEnumField,
27 ByteEnumField,
28 ByteField,
29 ConditionalField,
30 FCSField,
31 FieldLenField,
32 FieldListField,
33 FlagsField,
34 IntField,
35 LEFieldLenField,
36 LEIntField,
37 LELongField,
38 LEShortEnumField,
39 LEShortField,
40 LESignedIntField,
41 MayEnd,
42 MultipleTypeField,
43 OUIField,
44 PacketField,
45 PacketListField,
46 ReversePadField,
47 ScalingField,
48 ShortField,
49 StrField,
50 StrFixedLenField,
51 StrLenField,
52 XByteField,
53 XStrFixedLenField,
54)
55from scapy.ansmachine import AnsweringMachine
56from scapy.plist import PacketList
57from scapy.layers.l2 import Ether, LLC, MACField
58from scapy.layers.inet import IP, TCP
59from scapy.error import warning, log_loading
60from scapy.sendrecv import sniff, sendp
61
62
63if conf.crypto_valid:
64 from cryptography.hazmat.backends import default_backend
65 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
66else:
67 default_backend = Ciphers = algorithms = None
68 log_loading.info("Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption. (Dot11)") # noqa: E501
69
70
71#########
72# Prism #
73#########
74
75# http://www.martin.cc/linux/prism
76
77class PrismHeader(Packet):
78 """ iwpriv wlan0 monitor 3 """
79 name = "Prism header"
80 fields_desc = [LEIntField("msgcode", 68),
81 LEIntField("len", 144),
82 StrFixedLenField("dev", "", 16),
83 LEIntField("hosttime_did", 0),
84 LEShortField("hosttime_status", 0),
85 LEShortField("hosttime_len", 0),
86 LEIntField("hosttime", 0),
87 LEIntField("mactime_did", 0),
88 LEShortField("mactime_status", 0),
89 LEShortField("mactime_len", 0),
90 LEIntField("mactime", 0),
91 LEIntField("channel_did", 0),
92 LEShortField("channel_status", 0),
93 LEShortField("channel_len", 0),
94 LEIntField("channel", 0),
95 LEIntField("rssi_did", 0),
96 LEShortField("rssi_status", 0),
97 LEShortField("rssi_len", 0),
98 LEIntField("rssi", 0),
99 LEIntField("sq_did", 0),
100 LEShortField("sq_status", 0),
101 LEShortField("sq_len", 0),
102 LEIntField("sq", 0),
103 LEIntField("signal_did", 0),
104 LEShortField("signal_status", 0),
105 LEShortField("signal_len", 0),
106 LESignedIntField("signal", 0),
107 LEIntField("noise_did", 0),
108 LEShortField("noise_status", 0),
109 LEShortField("noise_len", 0),
110 LEIntField("noise", 0),
111 LEIntField("rate_did", 0),
112 LEShortField("rate_status", 0),
113 LEShortField("rate_len", 0),
114 LEIntField("rate", 0),
115 LEIntField("istx_did", 0),
116 LEShortField("istx_status", 0),
117 LEShortField("istx_len", 0),
118 LEIntField("istx", 0),
119 LEIntField("frmlen_did", 0),
120 LEShortField("frmlen_status", 0),
121 LEShortField("frmlen_len", 0),
122 LEIntField("frmlen", 0),
123 ]
124
125 def answers(self, other):
126 if isinstance(other, PrismHeader):
127 return self.payload.answers(other.payload)
128 else:
129 return self.payload.answers(other)
130
131############
132# RadioTap #
133############
134
135# https://www.radiotap.org/
136
137# Note: Radiotap alignment is crazy. See the doc:
138# https://www.radiotap.org/#alignment-in-radiotap
139
140# RadioTap constants
141
142
143_rt_present = ['TSFT', 'Flags', 'Rate', 'Channel', 'FHSS', 'dBm_AntSignal',
144 'dBm_AntNoise', 'Lock_Quality', 'TX_Attenuation',
145 'dB_TX_Attenuation', 'dBm_TX_Power', 'Antenna',
146 'dB_AntSignal', 'dB_AntNoise', 'RXFlags', 'TXFlags',
147 'b17', 'b18', 'ChannelPlus', 'MCS', 'A_MPDU',
148 'VHT', 'timestamp', 'HE', 'HE_MU', 'HE_MU_other_user',
149 'zero_length_psdu', 'L_SIG', 'TLV',
150 'RadiotapNS', 'VendorNS', 'Ext']
151
152# Note: Inconsistencies with wireshark
153# Wireshark ignores the suggested fields, whereas we implement some of them
154# (some are well-used even though not accepted)
155# However, flags that conflicts with Wireshark are not and MUST NOT be
156# implemented -> b17, b18
157
158_rt_flags = ['CFP', 'ShortPreamble', 'wep', 'fragment', 'FCS', 'pad',
159 'badFCS', 'ShortGI']
160
161_rt_channelflags = ['res1', 'res2', 'res3', 'res4', 'Turbo', 'CCK',
162 'OFDM', '2GHz', '5GHz', 'Passive', 'Dynamic_CCK_OFDM',
163 'GFSK', 'GSM', 'StaticTurbo', '10MHz', '5MHz']
164
165_rt_rxflags = ["res1", "BAD_PLCP", "res2"]
166
167_rt_txflags = ["TX_FAIL", "CTS", "RTS", "NOACK", "NOSEQ", "ORDER"]
168
169_rt_channelflags2 = ['res1', 'res2', 'res3', 'res4', 'Turbo', 'CCK',
170 'OFDM', '2GHz', '5GHz', 'Passive', 'Dynamic_CCK_OFDM',
171 'GFSK', 'GSM', 'StaticTurbo', '10MHz', '5MHz',
172 '20MHz', '40MHz_ext_channel_above',
173 '40MHz_ext_channel_below',
174 'res5', 'res6', 'res7', 'res8', 'res9']
175
176_rt_tsflags = ['32-bit_counter', 'Accuracy', 'res1', 'res2', 'res3',
177 'res4', 'res5', 'res6']
178
179_rt_knownmcs = ['MCS_bandwidth', 'MCS_index', 'guard_interval', 'HT_format',
180 'FEC_type', 'STBC_streams', 'Ness', 'Ness_MSB']
181
182_rt_bandwidth = {0: "20MHz", 1: "40MHz", 2: "ht40Mhz-", 3: "ht40MHz+"}
183
184_rt_a_mpdu_flags = ['Report0Subframe', 'Is0Subframe', 'KnownLastSubframe',
185 'LastSubframe', 'CRCerror', 'EOFsubframe', 'KnownEOF',
186 'res1', 'res2', 'res3', 'res4', 'res5', 'res6', 'res7',
187 'res8']
188
189_rt_vhtbandwidth = {
190 0: "20MHz", 1: "40MHz", 2: "40MHz", 3: "40MHz", 4: "80MHz", 5: "80MHz",
191 6: "80MHz", 7: "80MHz", 8: "80MHz", 9: "80MHz", 10: "80MHz", 11: "160MHz",
192 12: "160MHz", 13: "160MHz", 14: "160MHz", 15: "160MHz", 16: "160MHz",
193 17: "160MHz", 18: "160MHz", 19: "160MHz", 20: "160MHz", 21: "160MHz",
194 22: "160MHz", 23: "160MHz", 24: "160MHz", 25: "160MHz"
195}
196
197_rt_knownvht = ['STBC', 'TXOP_PS_NOT_ALLOWED', 'GuardInterval', 'SGINsysmDis',
198 'LDPCextraOFDM', 'Beamformed', 'Bandwidth', 'GroupID',
199 'PartialAID',
200 'res1', 'res2', 'res3', 'res4', 'res5', 'res6', 'res7']
201
202_rt_presentvht = ['STBC', 'TXOP_PS_NOT_ALLOWED', 'GuardInterval',
203 'SGINsysmDis', 'LDPCextraOFDM', 'Beamformed',
204 'res1', 'res2']
205
206_rt_hemuother_per_user_known = [
207 'user field position',
208 'STA-ID',
209 'NSTS',
210 'Tx Beamforming',
211 'Spatial Configuration',
212 'MCS',
213 'DCM',
214 'Coding',
215]
216
217
218# Radiotap utils
219
220# Note: extended presence masks are dissected pretty dumbly by
221# Wireshark.
222
223def _next_radiotap_extpm(pkt, lst, cur, s):
224 """Generates the next RadioTapExtendedPresenceMask"""
225 if cur is None or (cur.present and cur.present.Ext):
226 st = len(lst) + (cur is not None)
227 return lambda *args: RadioTapExtendedPresenceMask(*args, index=st)
228 return None
229
230
231class RadioTapExtendedPresenceMask(Packet):
232 """RadioTapExtendedPresenceMask should be instantiated by passing an
233 `index=` kwarg, stating which place the item has in the list.
234
235 Passing index will update the b[x] fields accordingly to the index.
236 e.g.
237 >>> a = RadioTapExtendedPresenceMask(present="b0+b12+b29+Ext")
238 >>> b = RadioTapExtendedPresenceMask(index=1, present="b33+b45+b59+b62")
239 >>> pkt = RadioTap(present="Ext", Ext=[a, b])
240 """
241 name = "RadioTap Extended presence mask"
242 fields_desc = [FlagsField('present', None, -32,
243 ["b%s" % i for i in range(0, 31)] + ["Ext"])]
244
245 def __init__(self, _pkt=None, index=0, **kwargs):
246 self._restart_indentation(index)
247 Packet.__init__(self, _pkt, **kwargs)
248
249 def _restart_indentation(self, index):
250 st = index * 32
251 self.fields_desc[0].names = ["b%s" % (i + st) for i in range(0, 31)] + ["Ext"] # noqa: E501
252
253 def guess_payload_class(self, pay):
254 return conf.padding_layer
255
256
257# This is still unimplemented in Wireshark
258# https://www.radiotap.org/fields/TLV.html
259class RadioTapTLV(Packet):
260 fields_desc = [
261 LEShortEnumField("type", 0, _rt_present),
262 LEShortField("length", None),
263 ConditionalField(
264 OUIField("oui", 0),
265 lambda pkt: pkt.type == 30 # VendorNS
266 ),
267 ConditionalField(
268 ByteField("subtype", 0),
269 lambda pkt: pkt.type == 30
270 ),
271 ConditionalField(
272 LEShortField("presence_type", 0),
273 lambda pkt: pkt.type == 30
274 ),
275 ConditionalField(
276 LEShortField("reserved", 0),
277 lambda pkt: pkt.type == 30
278 ),
279 StrLenField("data", b"",
280 length_from=lambda pkt: pkt.length),
281 StrLenField("pad", None, length_from=lambda pkt: -pkt.length % 4)
282 ]
283
284 def post_build(self, pkt, pay):
285 if self.length is None:
286 pkt = pkt[:2] + struct.pack("<H", len(self.data)) + pkt[4:]
287 if self.pad is None:
288 pkt += b"\x00" * (-len(self.data) % 4)
289 return pkt + pay
290
291 def extract_padding(self, s):
292 return "", s
293
294
295# RADIOTAP
296
297class RadioTap(Packet):
298 name = "RadioTap"
299 deprecated_fields = {
300 "Channel": ("ChannelFrequency", "2.4.3"),
301 "ChannelFlags2": ("ChannelPlusFlags", "2.4.3"),
302 "ChannelNumber": ("ChannelPlusNumber", "2.4.3"),
303 }
304 fields_desc = [
305 ByteField('version', 0),
306 ByteField('pad', 0),
307 LEShortField('len', None),
308 FlagsField('present', None, -32, _rt_present), # noqa: E501
309 # Extended presence mask
310 ConditionalField(PacketListField("Ext", [], next_cls_cb=_next_radiotap_extpm), lambda pkt: pkt.present and pkt.present.Ext), # noqa: E501
311 # RadioTap fields - each starts with a ReversePadField
312 # to handle padding
313
314 # TSFT
315 ConditionalField(
316 ReversePadField(
317 LELongField("mac_timestamp", 0),
318 8
319 ),
320 lambda pkt: pkt.present and pkt.present.TSFT),
321 # Flags
322 ConditionalField(
323 FlagsField("Flags", None, -8, _rt_flags),
324 lambda pkt: pkt.present and pkt.present.Flags),
325 # Rate
326 ConditionalField(
327 ScalingField("Rate", 0, scaling=0.5,
328 unit="Mbps", fmt="B"),
329 lambda pkt: pkt.present and pkt.present.Rate),
330 # Channel
331 ConditionalField(
332 ReversePadField(
333 LEShortField("ChannelFrequency", 0),
334 2
335 ),
336 lambda pkt: pkt.present and pkt.present.Channel),
337 ConditionalField(
338 FlagsField("ChannelFlags", None, -16, _rt_channelflags),
339 lambda pkt: pkt.present and pkt.present.Channel),
340 # dBm_AntSignal
341 ConditionalField(
342 ScalingField("dBm_AntSignal", 0,
343 unit="dBm", fmt="b"),
344 lambda pkt: pkt.present and pkt.present.dBm_AntSignal),
345 # dBm_AntNoise
346 ConditionalField(
347 ScalingField("dBm_AntNoise", 0,
348 unit="dBm", fmt="b"),
349 lambda pkt: pkt.present and pkt.present.dBm_AntNoise),
350 # Lock_Quality
351 ConditionalField(
352 ReversePadField(
353 LEShortField("Lock_Quality", 0),
354 2
355 ),
356 lambda pkt: pkt.present and pkt.present.Lock_Quality),
357 # Antenna
358 ConditionalField(
359 ByteField("Antenna", 0),
360 lambda pkt: pkt.present and pkt.present.Antenna),
361 # RX Flags
362 ConditionalField(
363 ReversePadField(
364 FlagsField("RXFlags", None, -16, _rt_rxflags),
365 2
366 ),
367 lambda pkt: pkt.present and pkt.present.RXFlags),
368 # TX Flags
369 ConditionalField(
370 ReversePadField(
371 FlagsField("TXFlags", None, -16, _rt_txflags),
372 2
373 ),
374 lambda pkt: pkt.present and pkt.present.TXFlags),
375 # ChannelPlus
376 ConditionalField(
377 ReversePadField(
378 FlagsField("ChannelPlusFlags", None, -32, _rt_channelflags2),
379 4
380 ),
381 lambda pkt: pkt.present and pkt.present.ChannelPlus),
382 ConditionalField(
383 LEShortField("ChannelPlusFrequency", 0),
384 lambda pkt: pkt.present and pkt.present.ChannelPlus),
385 ConditionalField(
386 ByteField("ChannelPlusNumber", 0),
387 lambda pkt: pkt.present and pkt.present.ChannelPlus),
388 # MCS
389 ConditionalField(
390 ReversePadField(
391 FlagsField("knownMCS", None, -8, _rt_knownmcs),
392 2
393 ),
394 lambda pkt: pkt.present and pkt.present.MCS),
395 ConditionalField(
396 BitField("Ness_LSB", 0, 1),
397 lambda pkt: pkt.present and pkt.present.MCS),
398 ConditionalField(
399 BitField("STBC_streams", 0, 2),
400 lambda pkt: pkt.present and pkt.present.MCS),
401 ConditionalField(
402 BitEnumField("FEC_type", 0, 1, {0: "BCC", 1: "LDPC"}),
403 lambda pkt: pkt.present and pkt.present.MCS),
404 ConditionalField(
405 BitEnumField("HT_format", 0, 1, {0: "mixed", 1: "greenfield"}),
406 lambda pkt: pkt.present and pkt.present.MCS),
407 ConditionalField(
408 BitEnumField("guard_interval", 0, 1, {0: "Long_GI", 1: "Short_GI"}), # noqa: E501
409 lambda pkt: pkt.present and pkt.present.MCS),
410 ConditionalField(
411 BitEnumField("MCS_bandwidth", 0, 2, _rt_bandwidth),
412 lambda pkt: pkt.present and pkt.present.MCS),
413 ConditionalField(
414 ByteField("MCS_index", 0),
415 lambda pkt: pkt.present and pkt.present.MCS),
416 # A_MPDU
417 ConditionalField(
418 ReversePadField(
419 LEIntField("A_MPDU_ref", 0),
420 4
421 ),
422 lambda pkt: pkt.present and pkt.present.A_MPDU),
423 ConditionalField(
424 FlagsField("A_MPDU_flags", None, -32, _rt_a_mpdu_flags),
425 lambda pkt: pkt.present and pkt.present.A_MPDU),
426 # VHT
427 ConditionalField(
428 ReversePadField(
429 FlagsField("KnownVHT", None, -16, _rt_knownvht),
430 2
431 ),
432 lambda pkt: pkt.present and pkt.present.VHT),
433 ConditionalField(
434 FlagsField("PresentVHT", None, -8, _rt_presentvht),
435 lambda pkt: pkt.present and pkt.present.VHT),
436 ConditionalField(
437 ByteEnumField("VHT_bandwidth", 0, _rt_vhtbandwidth),
438 lambda pkt: pkt.present and pkt.present.VHT),
439 ConditionalField(
440 StrFixedLenField("mcs_nss", 0, length=5),
441 lambda pkt: pkt.present and pkt.present.VHT),
442 ConditionalField(
443 ByteField("GroupID", 0),
444 lambda pkt: pkt.present and pkt.present.VHT),
445 ConditionalField(
446 ShortField("PartialAID", 0),
447 lambda pkt: pkt.present and pkt.present.VHT),
448 # timestamp
449 ConditionalField(
450 ReversePadField(
451 LELongField("timestamp", 0),
452 8
453 ),
454 lambda pkt: pkt.present and pkt.present.timestamp),
455 ConditionalField(
456 LEShortField("ts_accuracy", 0),
457 lambda pkt: pkt.present and pkt.present.timestamp),
458 ConditionalField(
459 BitEnumField("ts_unit", 0, 4, {
460 0: 'milliseconds',
461 1: 'microseconds',
462 2: 'nanoseconds'}),
463 lambda pkt: pkt.present and pkt.present.timestamp),
464 ConditionalField(
465 BitField("ts_position", 0, 4),
466 lambda pkt: pkt.present and pkt.present.timestamp),
467 ConditionalField(
468 FlagsField("ts_flags", None, 8, _rt_tsflags),
469 lambda pkt: pkt.present and pkt.present.timestamp),
470 # HE - XXX not complete
471 ConditionalField(
472 ReversePadField(
473 LEShortField("he_data1", 0),
474 2
475 ),
476 lambda pkt: pkt.present and pkt.present.HE),
477 ConditionalField(
478 LEShortField("he_data2", 0),
479 lambda pkt: pkt.present and pkt.present.HE),
480 ConditionalField(
481 LEShortField("he_data3", 0),
482 lambda pkt: pkt.present and pkt.present.HE),
483 ConditionalField(
484 LEShortField("he_data4", 0),
485 lambda pkt: pkt.present and pkt.present.HE),
486 ConditionalField(
487 LEShortField("he_data5", 0),
488 lambda pkt: pkt.present and pkt.present.HE),
489 ConditionalField(
490 LEShortField("he_data6", 0),
491 lambda pkt: pkt.present and pkt.present.HE),
492 # HE_MU
493 ConditionalField(
494 ReversePadField(
495 LEShortField("hemu_flags1", 0),
496 2
497 ),
498 lambda pkt: pkt.present and pkt.present.HE_MU),
499 ConditionalField(
500 LEShortField("hemu_flags2", 0),
501 lambda pkt: pkt.present and pkt.present.HE_MU),
502 ConditionalField(
503 FieldListField("RU_channel1", [], ByteField('', 0),
504 length_from=lambda x: 4),
505 lambda pkt: pkt.present and pkt.present.HE_MU),
506 ConditionalField(
507 FieldListField("RU_channel2", [], ByteField('', 0),
508 length_from=lambda x: 4),
509 lambda pkt: pkt.present and pkt.present.HE_MU),
510 # HE_MU_other_user
511 ConditionalField(
512 ReversePadField(
513 LEShortField("hemuou_per_user_1", 0x7fff),
514 2
515 ),
516 lambda pkt: pkt.present and pkt.present.HE_MU_other_user),
517 ConditionalField(
518 LEShortField("hemuou_per_user_2", 0x003f),
519 lambda pkt: pkt.present and pkt.present.HE_MU_other_user),
520 ConditionalField(
521 ByteField("hemuou_per_user_position", 0),
522 lambda pkt: pkt.present and pkt.present.HE_MU_other_user),
523 ConditionalField(
524 FlagsField("hemuou_per_user_known", 0, -16,
525 _rt_hemuother_per_user_known),
526 lambda pkt: pkt.present and pkt.present.HE_MU_other_user),
527 # L_SIG
528 ConditionalField(
529 ReversePadField(
530 FlagsField("lsig_data1", 0, -16, ["rate", "length"]),
531 2
532 ),
533 lambda pkt: pkt.present and pkt.present.L_SIG),
534 ConditionalField(
535 BitField("lsig_length", 0, 12, tot_size=-2),
536 lambda pkt: pkt.present and pkt.present.L_SIG),
537 ConditionalField(
538 BitField("lsig_rate", 0, 4, end_tot_size=-2),
539 lambda pkt: pkt.present and pkt.present.L_SIG),
540 # TLV fields
541 ConditionalField(
542 ReversePadField(
543 PacketListField("tlvs", [], RadioTapTLV),
544 4
545 ),
546 lambda pkt: pkt.present and pkt.present.TLV,
547 ),
548 # Remaining
549 StrLenField('notdecoded', "", length_from=lambda pkt: 0)
550 ]
551
552 def guess_payload_class(self, payload):
553 if self.present and self.present.Flags and self.Flags.FCS:
554 return Dot11FCS
555 return Dot11
556
557 def post_dissect(self, s):
558 length = max(self.len - len(self.original) + len(s), 0)
559 self.notdecoded = s[:length]
560 return s[length:]
561
562 def post_build(self, p, pay):
563 if self.len is None:
564 p = p[:2] + struct.pack("!H", len(p))[::-1] + p[4:]
565 return p + pay
566
567
568##########
569# 802.11 #
570##########
571
572# Note:
573# 802.11-2016 includes the spec for
574# 802.11abdghijekrywnpzvus,ae,aa,ad,ac,af
575
576# 802.11-2016 9.2
577
578# 802.11-2016 9.2.4.1.3
579_dot11_subtypes = {
580 0: { # Management
581 0: "Association Request",
582 1: "Association Response",
583 2: "Reassociation Request",
584 3: "Reassociation Response",
585 4: "Probe Request",
586 5: "Probe Response",
587 6: "Timing Advertisement",
588 8: "Beacon",
589 9: "ATIM",
590 10: "Disassociation",
591 11: "Authentication",
592 12: "Deauthentication",
593 13: "Action",
594 14: "Action No Ack",
595 },
596 1: { # Control
597 2: "Trigger",
598 3: "TACK",
599 4: "Beamforming Report Poll",
600 5: "VHT/HE NDP Announcement",
601 6: "Control Frame Extension",
602 7: "Control Wrapper",
603 8: "Block Ack Request",
604 9: "Block Ack",
605 10: "PS-Poll",
606 11: "RTS",
607 12: "CTS",
608 13: "Ack",
609 14: "CF-End",
610 15: "CF-End+CF-Ack",
611 },
612 2: { # Data
613 0: "Data",
614 1: "Data+CF-Ack",
615 2: "Data+CF-Poll",
616 3: "Data+CF-Ack+CF-Poll",
617 4: "Null (no data)",
618 5: "CF-Ack (no data)",
619 6: "CF-Poll (no data)",
620 7: "CF-Ack+CF-Poll (no data)",
621 8: "QoS Data",
622 9: "QoS Data+CF-Ack",
623 10: "QoS Data+CF-Poll",
624 11: "QoS Data+CF-Ack+CF-Poll",
625 12: "QoS Null (no data)",
626 14: "QoS CF-Poll (no data)",
627 15: "QoS CF-Ack+CF-Poll (no data)"
628 },
629 3: { # Extension
630 0: "DMG Beacon",
631 1: "S1G Beacon"
632 }
633}
634
635_dot11_cfe = {
636 2: "Poll",
637 3: "SPR",
638 4: "Grant",
639 5: "DMG CTS",
640 6: "DMG DTS",
641 7: "Grant Ack",
642 8: "SSW",
643 9: "SSW-Feedback",
644 10: "SSW-Ack",
645}
646
647
648_dot11_addr_meaning = [
649 [ # Management: 802.11-2016 9.3.3.2
650 "RA=DA", "TA=SA", "BSSID/STA", None,
651 ],
652 [ # Control
653 "RA", "TA", None, None
654 ],
655 [ # Data: 802.11-2016 9.3.2.1: Table 9-26
656 [["RA=DA", "RA=DA"], ["RA=BSSID", "RA"]],
657 [["TA=SA", "TA=BSSID"], ["TA=SA", "TA"]],
658 [["BSSID", "SA"], ["DA", "DA"]],
659 [[None, None], ["SA", "BSSID"]],
660 ],
661 [ # Extension
662 "BSSID", None, None, None
663 ],
664]
665
666
667class _Dot11MacField(MACField):
668 """
669 A MACField that displays the address type depending on the
670 802.11 flags
671 """
672 __slots__ = ["index"]
673
674 def __init__(self, name, default, index):
675 self.index = index
676 super(_Dot11MacField, self).__init__(name, default)
677
678 def i2repr(self, pkt, val):
679 s = super(_Dot11MacField, self).i2repr(pkt, val)
680 meaning = pkt.address_meaning(self.index)
681 if meaning:
682 return "%s (%s)" % (s, meaning)
683 return s
684
685
686# 802.11-2016 9.2.4.1.1
687class Dot11(Packet):
688 name = "802.11"
689 fields_desc = [
690 BitMultiEnumField("subtype", 0, 4, _dot11_subtypes,
691 lambda pkt: pkt.type),
692 BitEnumField("type", 0, 2, ["Management", "Control", "Data",
693 "Extension"]),
694 BitField("proto", 0, 2),
695 ConditionalField(
696 BitEnumField("cfe", 0, 4, _dot11_cfe),
697 lambda pkt: (pkt.type, pkt.subtype) == (1, 6)
698 ),
699 MultipleTypeField(
700 [
701 (
702 FlagsField("FCfield", 0, 4,
703 ["pw-mgt", "MD", "protected", "order"]),
704 lambda pkt: (pkt.type, pkt.subtype) == (1, 6)
705 )
706 ],
707 FlagsField("FCfield", 0, 8,
708 ["to-DS", "from-DS", "MF", "retry",
709 "pw-mgt", "MD", "protected", "order"])
710 ),
711 ShortField("ID", 0),
712 _Dot11MacField("addr1", ETHER_ANY, 1),
713 ConditionalField(
714 _Dot11MacField("addr2", ETHER_ANY, 2),
715 lambda pkt: (pkt.type != 1 or
716 pkt.subtype in [0x4, 0x5, 0x6, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf]),
717 ),
718 ConditionalField(
719 _Dot11MacField("addr3", ETHER_ANY, 3),
720 lambda pkt: (pkt.type in [0, 2] or
721 ((pkt.type, pkt.subtype) == (1, 6) and pkt.cfe == 6)),
722 ),
723 ConditionalField(LEShortField("SC", 0), lambda pkt: pkt.type != 1),
724 ConditionalField(
725 _Dot11MacField("addr4", ETHER_ANY, 4),
726 lambda pkt: (pkt.type == 2 and
727 pkt.FCfield & 3 == 3), # from-DS+to-DS
728 )
729 ]
730
731 def mysummary(self):
732 # Supports both Dot11 and Dot11FCS
733 return self.sprintf("802.11 %%%s.type%% %%%s.subtype%% %%%s.addr2%% > %%%s.addr1%%" % ((self.__class__.__name__,) * 4)) # noqa: E501
734
735 def guess_payload_class(self, payload):
736 if self.type == 0x02 and (
737 0x08 <= self.subtype <= 0xF and self.subtype != 0xD):
738 return Dot11QoS
739 elif self.FCfield.protected:
740 # When a frame is handled by encryption, the Protected Frame bit
741 # (previously called WEP bit) is set to 1, and the Frame Body
742 # begins with the appropriate cryptographic header.
743 return Dot11Encrypted
744 else:
745 return Packet.guess_payload_class(self, payload)
746
747 def answers(self, other):
748 if isinstance(other, Dot11):
749 if self.type == 0: # management
750 if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA # noqa: E501
751 return 0
752 if (other.subtype, self.subtype) in [(0, 1), (2, 3), (4, 5)]:
753 return 1
754 if self.subtype == other.subtype == 11: # auth
755 return self.payload.answers(other.payload)
756 elif self.type == 1: # control
757 return 0
758 elif self.type == 2: # data
759 return self.payload.answers(other.payload)
760 elif self.type == 3: # reserved
761 return 0
762 return 0
763
764 def address_meaning(self, index):
765 """
766 Return the meaning of the address[index] considering the context
767 """
768 if index not in [1, 2, 3, 4]:
769 raise ValueError("Wrong index: should be [1, 2, 3, 4]")
770 index = index - 1
771 if self.type == 0: # Management
772 return _dot11_addr_meaning[0][index]
773 elif self.type == 1: # Control
774 if (self.type, self.subtype) == (1, 6) and self.cfe == 6:
775 return ["RA", "NAV-SA", "NAV-DA"][index]
776 return _dot11_addr_meaning[1][index]
777 elif self.type == 2: # Data
778 meaning = _dot11_addr_meaning[2][index][
779 self.FCfield.to_DS
780 ][self.FCfield.from_DS]
781 if meaning and index in [2, 3]: # Address 3-4
782 if isinstance(self.payload, Dot11QoS):
783 # MSDU and Short A-MSDU
784 if self.payload.A_MSDU_Present:
785 meaning = "BSSID"
786 return meaning
787 elif self.type == 3: # Extension
788 return _dot11_addr_meaning[3][index]
789 return None
790
791 def unwep(self, key=None, warn=1):
792 if self.FCfield & 0x40 == 0:
793 if warn:
794 warning("No WEP to remove")
795 return
796 if isinstance(self.payload.payload, NoPayload):
797 if key or conf.wepkey:
798 self.payload.decrypt(key)
799 if isinstance(self.payload.payload, NoPayload):
800 if warn:
801 warning("Dot11 can't be decrypted. Check conf.wepkey.")
802 return
803 self.FCfield &= ~0x40
804 self.payload = self.payload.payload
805
806
807class Dot11FCS(Dot11):
808 name = "802.11-FCS"
809 match_subclass = True
810 fields_desc = Dot11.fields_desc + [FCSField("fcs", None, fmt="<I")]
811
812 def compute_fcs(self, s):
813 return struct.pack("!I", crc32(s) & 0xffffffff)[::-1]
814
815 def post_build(self, p, pay):
816 p += pay
817 if self.fcs is None:
818 p = p[:-4] + self.compute_fcs(p[:-4])
819 return p
820
821
822class Dot11QoS(Packet):
823 name = "802.11 QoS"
824 fields_desc = [BitField("A_MSDU_Present", 0, 1),
825 BitField("Ack_Policy", 0, 2),
826 BitField("EOSP", 0, 1),
827 BitField("TID", 0, 4),
828 ByteField("TXOP", 0)]
829
830 def guess_payload_class(self, payload):
831 if isinstance(self.underlayer, Dot11):
832 if self.underlayer.FCfield.protected:
833 return Dot11Encrypted
834 return Packet.guess_payload_class(self, payload)
835
836
837capability_list = ["res8", "res9", "short-slot", "res11",
838 "res12", "DSSS-OFDM", "res14", "res15",
839 "ESS", "IBSS", "CFP", "CFP-req",
840 "privacy", "short-preamble", "PBCC", "agility"]
841
842reason_code = {0: "reserved", 1: "unspec", 2: "auth-expired",
843 3: "deauth-ST-leaving",
844 4: "inactivity", 5: "AP-full", 6: "class2-from-nonauth",
845 7: "class3-from-nonass", 8: "disas-ST-leaving",
846 9: "ST-not-auth"}
847
848status_code = {0: "success", 1: "failure", 10: "cannot-support-all-cap",
849 11: "inexist-asso", 12: "asso-denied", 13: "algo-unsupported",
850 14: "bad-seq-num", 15: "challenge-failure",
851 16: "timeout", 17: "AP-full", 18: "rate-unsupported"}
852
853
854class _Dot11EltUtils(Packet):
855 """
856 Contains utils for classes that have Dot11Elt as payloads
857 """
858 def network_stats(self):
859 """Return a dictionary containing a summary of the Dot11
860 elements fields
861 """
862 summary = {}
863 crypto = set()
864 p = self.payload
865 while isinstance(p, Dot11Elt):
866 # Avoid overriding already-set SSID values because it is not part
867 # of the standard and it protects from parsing bugs,
868 # see https://github.com/secdev/scapy/issues/2683
869 if p.ID == 0 and "ssid" not in summary:
870 summary["ssid"] = plain_str(p.info)
871 elif p.ID == 3:
872 summary["channel"] = ord(p.info)
873 elif isinstance(p, Dot11EltCountry):
874 summary["country"] = plain_str(p.country_string[:2])
875 country_descriptor_types = {
876 b"I": "Indoor",
877 b"O": "Outdoor",
878 b"X": "Non-country",
879 b"\xff": "Ignored"
880 }
881 summary["country_desc_type"] = country_descriptor_types.get(
882 p.country_string[-1:]
883 )
884 elif isinstance(p, Dot11EltRates):
885 rates = [(x & 0x7f) / 2. for x in p.rates]
886 if "rates" in summary:
887 summary["rates"].extend(rates)
888 else:
889 summary["rates"] = rates
890 elif isinstance(p, Dot11EltRSN):
891 wpa_version = "WPA2"
892 # WPA3-only:
893 # - AP shall at least enable AKM suite selector 00-0F-AC:8
894 # - AP shall not enable AKM suite selector 00-0F-AC:2 and
895 # 00-0F-AC:6
896 # - AP shall set MFPC and MFPR to 1
897 # - AP shall not enable WEP and TKIP
898 # WPA3-transition:
899 # - AP shall at least enable AKM suite selector 00-0F-AC:2
900 # and 00-0F-AC:8
901 # - AP shall set MFPC to 1 and MFPR to 0
902 if any(x.suite == 8 for x in p.akm_suites) and \
903 all(x.suite not in [2, 6] for x in p.akm_suites) and \
904 p.mfp_capable and p.mfp_required and \
905 all(x.cipher not in [1, 2, 5]
906 for x in p.pairwise_cipher_suites):
907 # WPA3 only mode
908 wpa_version = "WPA3"
909 elif any(x.suite == 8 for x in p.akm_suites) and \
910 any(x.suite == 2 for x in p.akm_suites) and \
911 p.mfp_capable and not p.mfp_required:
912 # WPA3 transition mode
913 wpa_version = "WPA3-transition"
914 # Append suite
915 if p.akm_suites:
916 auth = p.akm_suites[0].sprintf("%suite%")
917 crypto.add(wpa_version + "/%s" % auth)
918 else:
919 crypto.add(wpa_version)
920 elif p.ID == 221:
921 if isinstance(p, Dot11EltMicrosoftWPA):
922 if p.akm_suites:
923 auth = p.akm_suites[0].sprintf("%suite%")
924 crypto.add("WPA/%s" % auth)
925 else:
926 crypto.add("WPA")
927 p = p.payload
928 if not crypto and hasattr(self, "cap"):
929 if self.cap.privacy:
930 crypto.add("WEP")
931 else:
932 crypto.add("OPN")
933 if crypto:
934 summary["crypto"] = crypto
935 return summary
936
937
938#############
939# 802.11 IE #
940#############
941
942# 802.11-2016 - 9.4.2
943
944_dot11_info_elts_ids = {
945 0: "SSID",
946 1: "Supported Rates",
947 2: "FHset",
948 3: "DSSS Set",
949 4: "CF Set",
950 5: "TIM",
951 6: "IBSS Set",
952 7: "Country",
953 10: "Request",
954 11: "BSS Load",
955 12: "EDCA Set",
956 13: "TSPEC",
957 14: "TCLAS",
958 15: "Schedule",
959 16: "Challenge text",
960 32: "Power Constraint",
961 33: "Power Capability",
962 36: "Supported Channels",
963 37: "Channel Switch Announcement",
964 42: "ERP",
965 45: "HT Capabilities",
966 46: "QoS Capability",
967 48: "RSN",
968 50: "Extended Supported Rates",
969 52: "Neighbor Report",
970 61: "HT Operation",
971 74: "Overlapping BSS Scan Parameters",
972 107: "Interworking",
973 127: "Extended Capabilities",
974 191: "VHT Capabilities",
975 192: "VHT Operation",
976 221: "Vendor Specific"
977}
978
979# Backward compatibility
980_dot11_elt_deprecated_names = {
981 "Rates": 1,
982 "DSset": 3,
983 "CFset": 4,
984 "IBSSset": 6,
985 "challenge": 16,
986 "PowerCapability": 33,
987 "Channels": 36,
988 "ERPinfo": 42,
989 "HTinfo": 45,
990 "RSNinfo": 48,
991 "ESRates": 50,
992 "ExtendendCapatibilities": 127,
993 "VHTCapabilities": 191,
994 "Vendor": 221,
995}
996
997_dot11_info_elts_ids_rev = {v: k for k, v in _dot11_info_elts_ids.items()}
998_dot11_info_elts_ids_rev.update(_dot11_elt_deprecated_names)
999_dot11_id_enum = (
1000 lambda x: _dot11_info_elts_ids.get(x, x),
1001 lambda x: _dot11_info_elts_ids_rev.get(x, x)
1002)
1003
1004
1005# 802.11-2020 9.4.2.1
1006
1007class Dot11Elt(Packet):
1008 """
1009 A Generic 802.11 Element
1010 """
1011 __slots__ = ["info"]
1012 name = "802.11 Information Element"
1013 fields_desc = [ByteEnumField("ID", 0, _dot11_id_enum),
1014 FieldLenField("len", None, "info", "B"),
1015 StrLenField("info", "", length_from=lambda x: x.len,
1016 max_length=255)]
1017 show_indent = 0
1018
1019 def __setattr__(self, attr, val):
1020 if attr == "info":
1021 # Will be caught by __slots__: we need an extra call
1022 try:
1023 self.setfieldval(attr, val)
1024 except AttributeError:
1025 pass
1026 super(Dot11Elt, self).__setattr__(attr, val)
1027
1028 def mysummary(self):
1029 if self.ID == 0:
1030 ssid = plain_str(self.info)
1031 return "SSID='%s'" % ssid, [Dot11]
1032 else:
1033 return ""
1034
1035 registered_ies = {}
1036
1037 @classmethod
1038 def register_variant(cls, id=None):
1039 id = id or cls.ID.default
1040 if id not in cls.registered_ies:
1041 cls.registered_ies[id] = cls
1042
1043 @classmethod
1044 def dispatch_hook(cls, _pkt=None, *args, **kargs):
1045 if _pkt:
1046 _id = ord(_pkt[:1])
1047 idcls = cls.registered_ies.get(_id, cls)
1048 if idcls.dispatch_hook != cls.dispatch_hook:
1049 # Vendor has its own dispatch_hook
1050 return idcls.dispatch_hook(_pkt=_pkt, *args, **kargs)
1051 cls = idcls
1052 return cls
1053
1054 def pre_dissect(self, s):
1055 # Backward compatibility: add info to all elements
1056 # This allows to introduce new Dot11Elt classes without breaking
1057 # previous code
1058 if len(s) >= 3:
1059 length = orb(s[1])
1060 if length > 0 and length <= 255:
1061 self.info = s[2:2 + length]
1062 return s
1063
1064 def post_build(self, p, pay):
1065 if self.len is None:
1066 p = p[:1] + chb(len(p) - 2) + p[2:]
1067 return p + pay
1068
1069
1070# 802.11-2020 9.4.2.4
1071
1072class Dot11EltDSSSet(Dot11Elt):
1073 name = "802.11 DSSS Parameter Set"
1074 match_subclass = True
1075 fields_desc = [
1076 ByteEnumField("ID", 3, _dot11_id_enum),
1077 ByteField("len", 1),
1078 ByteField("channel", 0),
1079 ]
1080
1081
1082# 802.11-2020 9.4.2.11
1083
1084class Dot11EltERP(Dot11Elt):
1085 name = "802.11 ERP"
1086 match_subclass = True
1087 fields_desc = [
1088 ByteEnumField("ID", 42, _dot11_id_enum),
1089 ByteField("len", 1),
1090 BitField("NonERP_Present", 0, 1),
1091 BitField("Use_Protection", 0, 1),
1092 BitField("Barker_Preamble_Mode", 0, 1),
1093 BitField("res", 0, 5),
1094 ]
1095
1096
1097# 802.11-2020 9.4.2.24.2
1098
1099class RSNCipherSuite(Packet):
1100 name = "Cipher suite"
1101 fields_desc = [
1102 OUIField("oui", 0x000fac),
1103 ByteEnumField("cipher", 0x04, {
1104 0x00: "Use group cipher suite",
1105 0x01: "WEP-40",
1106 0x02: "TKIP",
1107 0x03: "OCB",
1108 0x04: "CCMP-128",
1109 0x05: "WEP-104",
1110 0x06: "BIP-CMAC-128",
1111 0x07: "Group addressed traffic not allowed",
1112 0x08: "GCMP-128",
1113 0x09: "GCMP-256",
1114 0x0A: "CCMP-256",
1115 0x0B: "BIP-GMAC-128",
1116 0x0C: "BIP-GMAC-256",
1117 0x0D: "BIP-CMAC-256"
1118 })
1119 ]
1120
1121 def extract_padding(self, s):
1122 return "", s
1123
1124
1125# 802.11-2020 9.4.2.24.3
1126
1127class AKMSuite(Packet):
1128 name = "AKM suite"
1129 fields_desc = [
1130 OUIField("oui", 0x000fac),
1131 ByteEnumField("suite", 0x01, {
1132 0x00: "Reserved",
1133 0x01: "802.1X",
1134 0x02: "PSK",
1135 0x03: "FT-802.1X",
1136 0x04: "FT-PSK",
1137 0x05: "WPA-SHA256",
1138 0x06: "PSK-SHA256",
1139 0x07: "TDLS",
1140 0x08: "SAE",
1141 0x09: "FT-SAE",
1142 0x0A: "AP-PEER-KEY",
1143 0x0B: "WPA-SHA256-SUITE-B",
1144 0x0C: "WPA-SHA384-SUITE-B",
1145 0x0D: "FT-802.1X-SHA384",
1146 0x0E: "FILS-SHA256",
1147 0x0F: "FILS-SHA384",
1148 0x10: "FT-FILS-SHA256",
1149 0x11: "FT-FILS-SHA384",
1150 0x12: "OWE"
1151 })
1152 ]
1153
1154 def extract_padding(self, s):
1155 return "", s
1156
1157
1158# 802.11-2020 9.4.2.24.5
1159
1160class PMKIDListPacket(Packet):
1161 name = "PMKIDs"
1162 fields_desc = [
1163 LEFieldLenField("nb_pmkids", None, count_of="pmkid_list"),
1164 FieldListField(
1165 "pmkid_list",
1166 None,
1167 XStrFixedLenField("", "", length=16),
1168 count_from=lambda pkt: pkt.nb_pmkids
1169 )
1170 ]
1171
1172 def extract_padding(self, s):
1173 return "", s
1174
1175
1176# 802.11-2020 9.4.2.24.1
1177
1178class Dot11EltRSN(Dot11Elt):
1179 name = "802.11 RSN information"
1180 match_subclass = True
1181 fields_desc = [
1182 ByteEnumField("ID", 48, _dot11_id_enum),
1183 ByteField("len", None),
1184 LEShortField("version", 1),
1185 PacketField("group_cipher_suite", RSNCipherSuite(), RSNCipherSuite),
1186 LEFieldLenField(
1187 "nb_pairwise_cipher_suites",
1188 None,
1189 count_of="pairwise_cipher_suites"
1190 ),
1191 PacketListField(
1192 "pairwise_cipher_suites",
1193 [RSNCipherSuite()],
1194 RSNCipherSuite,
1195 count_from=lambda p: p.nb_pairwise_cipher_suites
1196 ),
1197 LEFieldLenField(
1198 "nb_akm_suites",
1199 None,
1200 count_of="akm_suites"
1201 ),
1202 PacketListField(
1203 "akm_suites",
1204 [AKMSuite()],
1205 AKMSuite,
1206 count_from=lambda p: p.nb_akm_suites
1207 ),
1208 # RSN Capabilities
1209 # 802.11-2020 9.4.2.24.4
1210 BitField("mfp_capable", 1, 1),
1211 BitField("mfp_required", 1, 1),
1212 BitField("gtksa_replay_counter", 0, 2),
1213 BitField("ptksa_replay_counter", 0, 2),
1214 BitField("no_pairwise", 0, 1),
1215 BitField("pre_auth", 0, 1),
1216 BitField("reserved", 0, 1),
1217 BitField("ocvc", 0, 1),
1218 BitField("extended_key_id", 0, 1),
1219 BitField("pbac", 0, 1),
1220 BitField("spp_a_msdu_required", 0, 1),
1221 BitField("spp_a_msdu_capable", 0, 1),
1222 BitField("peer_key_enabled", 0, 1),
1223 BitField("joint_multiband_rsna", 0, 1),
1224 # Theoretically we could use mfp_capable/mfp_required to know if those
1225 # fields are present, but some implementations poorly implement it.
1226 # In practice, do as wireshark: guess using offset.
1227 ConditionalField(
1228 PacketField("pmkids", PMKIDListPacket(), PMKIDListPacket),
1229 lambda pkt: (
1230 True if pkt.len is None else
1231 pkt.len - (
1232 12 +
1233 (pkt.nb_pairwise_cipher_suites or 0) * 4 +
1234 (pkt.nb_akm_suites or 0) * 4
1235 ) >= 2
1236 )
1237 ),
1238 ConditionalField(
1239 PacketField("group_management_cipher_suite",
1240 RSNCipherSuite(cipher=0x6), RSNCipherSuite),
1241 lambda pkt: (
1242 True if pkt.len is None else
1243 pkt.len - (
1244 12 +
1245 (pkt.nb_pairwise_cipher_suites or 0) * 4 +
1246 (pkt.nb_akm_suites or 0) * 4 +
1247 (2 if pkt.pmkids else 0) +
1248 (pkt.pmkids and pkt.pmkids.nb_pmkids or 0) * 16
1249 ) >= 4
1250 )
1251 )
1252 ]
1253
1254
1255class Dot11EltCountryConstraintTriplet(Packet):
1256 name = "802.11 Country Constraint Triplet"
1257 fields_desc = [
1258 ByteField("first_channel_number", 1),
1259 ByteField("num_channels", 24),
1260 ByteField("mtp", 0)
1261 ]
1262
1263 def extract_padding(self, s):
1264 return b"", s
1265
1266
1267class Dot11EltCountry(Dot11Elt):
1268 name = "802.11 Country"
1269 match_subclass = True
1270 fields_desc = [
1271 ByteEnumField("ID", 7, _dot11_id_enum),
1272 ByteField("len", None),
1273 StrFixedLenField("country_string", b"\0\0\0", length=3),
1274 MayEnd(PacketListField(
1275 "descriptors",
1276 [],
1277 Dot11EltCountryConstraintTriplet,
1278 length_from=lambda pkt: (
1279 pkt.len - 3 - (pkt.len % 3)
1280 )
1281 )),
1282 # When this extension is last, padding appears to be omitted
1283 ConditionalField(
1284 ByteField("pad", 0),
1285 # The length should be 3 bytes per each triplet, and 3 bytes for the
1286 # country_string field. The standard dictates that the element length
1287 # must be even, so if the result is odd, add a padding byte.
1288 # Some transmitters don't comply with the standard, so instead of assuming
1289 # the length, we test whether there is a padding byte.
1290 # Some edge cases are still not covered, for example, if the tag length
1291 # (pkt.len) is an arbitrary number.
1292 lambda pkt: ((len(pkt.descriptors) + 1) % 2) if pkt.len is None else (pkt.len % 3) # noqa: E501
1293 )
1294 ]
1295
1296
1297class _RateField(ByteField):
1298 def i2repr(self, pkt, val):
1299 if val is None:
1300 return ""
1301 s = str((val & 0x7f) / 2.)
1302 if val & 0x80:
1303 s += "(B)"
1304 return s + " Mbps"
1305
1306
1307class Dot11EltRates(Dot11Elt):
1308 name = "802.11 Rates"
1309 match_subclass = True
1310 fields_desc = [
1311 ByteEnumField("ID", 1, _dot11_id_enum),
1312 ByteField("len", None),
1313 FieldListField(
1314 "rates",
1315 [0x82],
1316 _RateField("", 0),
1317 length_from=lambda p: p.len
1318 )
1319 ]
1320
1321
1322Dot11EltRates.register_variant(50) # Extended rates
1323
1324
1325class Dot11EltHTCapabilities(Dot11Elt):
1326 name = "802.11 HT Capabilities"
1327 match_subclass = True
1328 fields_desc = [
1329 ByteEnumField("ID", 45, _dot11_id_enum),
1330 ByteField("len", None),
1331 # HT Capabilities Info: 2B
1332 BitField("L_SIG_TXOP_Protection", 0, 1, tot_size=-2),
1333 BitField("Forty_Mhz_Intolerant", 0, 1),
1334 BitField("PSMP", 0, 1),
1335 BitField("DSSS_CCK", 0, 1),
1336 BitEnumField("Max_A_MSDU", 0, 1, {0: "3839 o", 1: "7935 o"}),
1337 BitField("Delayed_BlockAck", 0, 1),
1338 BitField("Rx_STBC", 0, 2),
1339 BitField("Tx_STBC", 0, 1),
1340 BitField("Short_GI_40Mhz", 0, 1),
1341 BitField("Short_GI_20Mhz", 0, 1),
1342 BitField("Green_Field", 0, 1),
1343 BitEnumField("SM_Power_Save", 0, 2,
1344 {0: "static SM", 1: "dynamic SM", 3: "disabled"}),
1345 BitEnumField("Supported_Channel_Width", 0, 1,
1346 {0: "20Mhz", 1: "20Mhz+40Mhz"}),
1347 BitField("LDPC_Coding_Capability", 0, 1, end_tot_size=-2),
1348 # A-MPDU Parameters: 1B
1349 BitField("res1", 0, 3, tot_size=-1),
1350 BitField("Min_MPDCU_Start_Spacing", 8, 3),
1351 BitField("Max_A_MPDU_Length_Exponent", 3, 2, end_tot_size=-1),
1352 # Supported MCS set: 16B
1353 BitField("res2", 0, 27, tot_size=-16),
1354 BitField("TX_Unequal_Modulation", 0, 1),
1355 BitField("TX_Max_Spatial_Streams", 0, 2),
1356 BitField("TX_RX_MCS_Set_Not_Equal", 0, 1),
1357 BitField("TX_MCS_Set_Defined", 0, 1),
1358 BitField("res3", 0, 6),
1359 BitField("RX_Highest_Supported_Data_Rate", 0, 10),
1360 BitField("res4", 0, 3),
1361 BitField("RX_MSC_Bitmask", 0, 77, end_tot_size=-16),
1362 # HT Extended capabilities: 2B
1363 BitField("res5", 0, 4, tot_size=-2),
1364 BitField("RD_Responder", 0, 1),
1365 BitField("HTC_HT_Support", 0, 1),
1366 BitField("MCS_Feedback", 0, 2),
1367 BitField("res6", 0, 5),
1368 BitField("PCO_Transition_Time", 0, 2),
1369 BitField("PCO", 0, 1, end_tot_size=-2),
1370 # TX Beamforming Capabilities TxBF: 4B
1371 BitField("res7", 0, 3, tot_size=-4),
1372 BitField("Channel_Estimation_Capability", 0, 2),
1373 BitField("CSI_max_n_Rows_Beamformer_Supported", 0, 2),
1374 BitField("Compressed_Steering_n_Beamformer_Antennas_Supported", 0, 2),
1375 BitField("Noncompressed_Steering_n_Beamformer_Antennas_Supported",
1376 0, 2),
1377 BitField("CSI_n_Beamformer_Antennas_Supported", 0, 2),
1378 BitField("Minimal_Grouping", 0, 2),
1379 BitField("Explicit_Compressed_Beamforming_Feedback", 0, 2),
1380 BitField("Explicit_Noncompressed_Beamforming_Feedback", 0, 2),
1381 BitField("Explicit_Transmit_Beamforming_CSI_Feedback", 0, 2),
1382 BitField("Explicit_Compressed_Steering", 0, 1),
1383 BitField("Explicit_Noncompressed_Steering", 0, 1),
1384 BitField("Explicit_CSI_Transmit_Beamforming", 0, 1),
1385 BitField("Calibration", 0, 2),
1386 BitField("Implicit_Trasmit_Beamforming", 0, 1),
1387 BitField("Transmit_NDP", 0, 1),
1388 BitField("Receive_NDP", 0, 1),
1389 BitField("Transmit_Staggered_Sounding", 0, 1),
1390 BitField("Receive_Staggered_Sounding", 0, 1),
1391 BitField("Implicit_Transmit_Beamforming_Receiving", 0, 1,
1392 end_tot_size=-4),
1393 # ASEL Capabilities: 1B
1394 FlagsField("ASEL", 0, 8, [
1395 "res",
1396 "Transmit_Sounding_PPDUs",
1397 "Receive_ASEL",
1398 "Antenna_Indices_Feedback",
1399 "Explicit_CSI_Feedback",
1400 "Explicit_CSI_Feedback_Based_Transmit_ASEL",
1401 "Antenna_Selection",
1402 ])
1403 ]
1404
1405
1406class Dot11EltVendorSpecific(Dot11Elt):
1407 name = "802.11 Vendor Specific"
1408 match_subclass = True
1409 fields_desc = [
1410 ByteEnumField("ID", 221, _dot11_id_enum),
1411 ByteField("len", None),
1412 OUIField("oui", 0x000000),
1413 StrLenField("info", "", length_from=lambda x: x.len - 3)
1414 ]
1415
1416 @classmethod
1417 def dispatch_hook(cls, _pkt=None, *args, **kargs):
1418 if _pkt:
1419 oui = struct.unpack("!I", b"\x00" + _pkt[2:5])[0]
1420 if oui == 0x0050f2: # Microsoft
1421 type_ = orb(_pkt[5])
1422 if type_ == 0x01:
1423 # MS WPA IE
1424 return Dot11EltMicrosoftWPA
1425 elif type_ == 0x02:
1426 # MS WME IE TODO
1427 # return Dot11EltMicrosoftWME
1428 pass
1429 elif type_ == 0x04:
1430 # MS WPS IE TODO
1431 # return Dot11EltWPS
1432 pass
1433 return Dot11EltVendorSpecific
1434 return cls
1435
1436
1437class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific):
1438 name = "802.11 Microsoft WPA"
1439 match_subclass = True
1440 ID = 221
1441 oui = 0x0050f2
1442 # It appears many WPA implementations ignore the fact
1443 # that this IE should only have a single cipher and auth suite
1444 fields_desc = Dot11EltVendorSpecific.fields_desc[:3] + [
1445 XByteField("type", 0x01)
1446 ] + Dot11EltRSN.fields_desc[2:8]
1447
1448
1449# 802.11-2016 9.4.2.19
1450
1451class Dot11EltCSA(Dot11Elt):
1452 name = "802.11 CSA Element"
1453 fields_desc = [
1454 ByteEnumField("ID", 37, _dot11_id_enum),
1455 ByteField("len", 3),
1456 ByteField("mode", 0),
1457 ByteField("new_channel", 0),
1458 ByteField("channel_switch_count", 0)
1459 ]
1460
1461
1462# 802.11-2016 9.4.2.59
1463
1464class Dot11EltOBSS(Dot11Elt):
1465 name = "802.11 OBSS Scan Parameters Element"
1466 fields_desc = [
1467 ByteEnumField("ID", 74, _dot11_id_enum),
1468 ByteField("len", 14),
1469 LEShortField("Passive_Dwell", 0),
1470 LEShortField("Active_Dwell", 0),
1471 LEShortField("Scan_Interval", 0),
1472 LEShortField("Passive_Total_Per_Channel", 0),
1473 LEShortField("Active_Total_Per_Channel", 0),
1474 LEShortField("Delay", 0),
1475 LEShortField("Activity_Threshold", 0),
1476 ]
1477
1478
1479# 802.11-2016 9.4.2.159
1480
1481class Dot11VHTOperationInfo(Packet):
1482 name = "802.11 VHT Operation Information"
1483 fields_desc = [
1484 ByteField("channel_width", 0),
1485 ByteField("channel_center0", 36),
1486 ByteField("channel_center1", 0),
1487 ]
1488
1489 def extract_padding(self, s):
1490 return "", s
1491
1492
1493class Dot11EltVHTOperation(Dot11Elt):
1494 name = "802.11 VHT Operation Element"
1495 fields_desc = [
1496 ByteEnumField("ID", 192, _dot11_id_enum),
1497 ByteField("len", 5),
1498 PacketField(
1499 "VHT_Operation_Info",
1500 Dot11VHTOperationInfo(),
1501 Dot11VHTOperationInfo
1502 ),
1503 FieldListField(
1504 "mcs_set",
1505 [0x00],
1506 BitField('SS', 0x00, size=2),
1507 count_from=lambda x: 8
1508 )
1509 ]
1510
1511
1512######################
1513# 802.11 Frame types #
1514######################
1515
1516# 802.11-2016 9.3
1517
1518class Dot11Beacon(_Dot11EltUtils):
1519 name = "802.11 Beacon"
1520 fields_desc = [LELongField("timestamp", 0),
1521 LEShortField("beacon_interval", 0x0064),
1522 FlagsField("cap", 0, 16, capability_list)]
1523
1524
1525class Dot11ATIM(Packet):
1526 name = "802.11 ATIM"
1527
1528
1529class Dot11Disas(Packet):
1530 name = "802.11 Disassociation"
1531 fields_desc = [LEShortEnumField("reason", 1, reason_code)]
1532
1533
1534class Dot11AssoReq(_Dot11EltUtils):
1535 name = "802.11 Association Request"
1536 fields_desc = [FlagsField("cap", 0, 16, capability_list),
1537 LEShortField("listen_interval", 0x00c8)]
1538
1539
1540class Dot11AssoResp(_Dot11EltUtils):
1541 name = "802.11 Association Response"
1542 fields_desc = [FlagsField("cap", 0, 16, capability_list),
1543 LEShortField("status", 0),
1544 LEShortField("AID", 0)]
1545
1546
1547class Dot11ReassoReq(_Dot11EltUtils):
1548 name = "802.11 Reassociation Request"
1549 fields_desc = [FlagsField("cap", 0, 16, capability_list),
1550 LEShortField("listen_interval", 0x00c8),
1551 MACField("current_AP", ETHER_ANY)]
1552
1553
1554class Dot11ReassoResp(Dot11AssoResp):
1555 name = "802.11 Reassociation Response"
1556
1557
1558class Dot11ProbeReq(_Dot11EltUtils):
1559 name = "802.11 Probe Request"
1560
1561
1562class Dot11ProbeResp(_Dot11EltUtils):
1563 name = "802.11 Probe Response"
1564 fields_desc = [LELongField("timestamp", 0),
1565 LEShortField("beacon_interval", 0x0064),
1566 FlagsField("cap", 0, 16, capability_list)]
1567
1568
1569class Dot11Auth(_Dot11EltUtils):
1570 name = "802.11 Authentication"
1571 fields_desc = [LEShortEnumField("algo", 0, ["open", "sharedkey"]),
1572 LEShortField("seqnum", 0),
1573 LEShortEnumField("status", 0, status_code)]
1574
1575 def answers(self, other):
1576 if self.algo != other.algo:
1577 return 0
1578
1579 if (
1580 self.seqnum == other.seqnum + 1 or
1581 (self.algo == 3 and self.seqnum == other.seqnum)
1582 ):
1583 return 1
1584 return 0
1585
1586
1587class Dot11Deauth(Packet):
1588 name = "802.11 Deauthentication"
1589 fields_desc = [LEShortEnumField("reason", 1, reason_code)]
1590
1591
1592class Dot11Ack(Packet):
1593 name = "802.11 Ack packet"
1594
1595
1596# 802.11-2016 9.4.1.11
1597
1598class Dot11Action(Packet):
1599 name = "802.11 Action"
1600 fields_desc = [
1601 ByteEnumField("category", 0x00, {
1602 0x00: "Spectrum Management",
1603 0x01: "QoS",
1604 0x02: "DLS",
1605 0x03: "Block",
1606 0x04: "Public",
1607 0x05: "Radio Measurement",
1608 0x06: "Fast BSS Transition",
1609 0x07: "HT",
1610 0x08: "SA Query",
1611 0x09: "Protected Dual of Public Action",
1612 0x0A: "WNM",
1613 0x0B: "Unprotected WNM",
1614 0x0C: "TDLS",
1615 0x0D: "Mesh",
1616 0x0E: "Multihop",
1617 0x0F: "Self-protected",
1618 0x10: "DMG",
1619 0x11: "Reserved Wi-Fi Alliance",
1620 0x12: "Fast Session Transfer",
1621 0x13: "Robust AV Streaming",
1622 0x14: "Unprotected DMG",
1623 0x15: "VHT"
1624 })
1625 ]
1626
1627
1628# 802.11-2016 9.6.14.1
1629
1630class Dot11WNM(Packet):
1631 name = "802.11 WNM Action"
1632 fields_desc = [
1633 ByteEnumField("action", 0x00, {
1634 0x00: "Event Request",
1635 0x01: "Event Report",
1636 0x02: "Diagnostic Request",
1637 0x03: "Diagnostic Report",
1638 0x04: "Location Configuration Request",
1639 0x05: "Location Configuration Response",
1640 0x06: "BSS Transition Management Query",
1641 0x07: "BSS Transition Management Request",
1642 0x08: "BSS Transition Management Response",
1643 0x09: "FMS Request",
1644 0x0A: "FMS Response",
1645 0x0B: "Collocated Interference Request",
1646 0x0C: "Collocated Interference Report",
1647 0x0D: "TFS Request",
1648 0x0E: "TFS Response",
1649 0x0F: "TFS Notify",
1650 0x10: "WNM Sleep Mode Request",
1651 0x11: "WNM Sleep Mode Response",
1652 0x12: "TIM Broadcast Request",
1653 0x13: "TIM Broadcast Response",
1654 0x14: "QoS Traffic Capability Update",
1655 0x15: "Channel Usage Request",
1656 0x16: "Channel Usage Response",
1657 0x17: "DMS Request",
1658 0x18: "DMS Response",
1659 0x19: "Timing Measurement Request",
1660 0x1A: "WNM Notification Request",
1661 0x1B: "WNM Notification Response",
1662 0x1C: "WNM-Notify Response"
1663 })
1664 ]
1665
1666
1667# 802.11-2016 9.4.2.37
1668
1669class SubelemTLV(Packet):
1670 fields_desc = [
1671 ByteField("type", 0),
1672 LEFieldLenField("len", None, fmt="B", length_of="value"),
1673 FieldListField(
1674 "value",
1675 [],
1676 ByteField('', 0),
1677 length_from=lambda p: p.len
1678 )
1679 ]
1680
1681
1682class BSSTerminationDuration(Packet):
1683 name = "BSS Termination Duration"
1684 fields_desc = [
1685 ByteField("id", 4),
1686 ByteField("len", 10),
1687 LELongField("TSF", 0),
1688 LEShortField("duration", 0)
1689 ]
1690
1691 def extract_padding(self, s):
1692 return "", s
1693
1694
1695class NeighborReport(Packet):
1696 name = "Neighbor Report"
1697 fields_desc = [
1698 ByteField("type", 0),
1699 ByteField("len", 13),
1700 MACField("BSSID", ETHER_ANY),
1701 # BSSID Information
1702 BitField("AP_reach", 0, 2, tot_size=-4),
1703 BitField("security", 0, 1),
1704 BitField("key_scope", 0, 1),
1705 BitField("capabilities", 0, 6),
1706 BitField("mobility", 0, 1),
1707 BitField("HT", 0, 1),
1708 BitField("VHT", 0, 1),
1709 BitField("FTM", 0, 1),
1710 BitField("reserved", 0, 18, end_tot_size=-4),
1711 # BSSID Information end
1712 ByteField("op_class", 0),
1713 ByteField("channel", 0),
1714 ByteField("phy_type", 0),
1715 ConditionalField(
1716 PacketListField(
1717 "subelems",
1718 SubelemTLV(),
1719 SubelemTLV,
1720 length_from=lambda p: p.len - 13
1721 ),
1722 lambda p: p.len > 13
1723 )
1724 ]
1725
1726
1727# 802.11-2016 9.6.14.9
1728
1729btm_request_mode = [
1730 "Preferred_Candidate_List_Included",
1731 "Abridged",
1732 "Disassociation_Imminent",
1733 "BSS_Termination_Included",
1734 "ESS_Disassociation_Imminent"
1735]
1736
1737
1738class Dot11BSSTMRequest(Packet):
1739 name = "BSS Transition Management Request"
1740 fields_desc = [
1741 ByteField("token", 0),
1742 FlagsField("mode", 0, 8, btm_request_mode),
1743 LEShortField("disassociation_timer", 0),
1744 ByteField("validity_interval", 0),
1745 ConditionalField(
1746 PacketField(
1747 "termination_duration",
1748 BSSTerminationDuration(),
1749 BSSTerminationDuration
1750 ),
1751 lambda p: p.mode and p.mode.BSS_Termination_Included
1752 ),
1753 ConditionalField(
1754 ByteField("url_len", 0),
1755 lambda p: p.mode and p.mode.ESS_Disassociation_Imminent
1756 ),
1757 ConditionalField(
1758 StrLenField("url", "", length_from=lambda p: p.url_len),
1759 lambda p: p.mode and p.mode.ESS_Disassociation_Imminent != 0
1760 ),
1761 ConditionalField(
1762 PacketListField(
1763 "neighbor_report",
1764 NeighborReport(),
1765 NeighborReport
1766 ),
1767 lambda p: p.mode and p.mode.Preferred_Candidate_List_Included
1768 )
1769 ]
1770
1771
1772# 802.11-2016 9.6.14.10
1773
1774btm_status_code = [
1775 "Accept",
1776 "Reject-Unspecified_reject_reason",
1777 "Reject-Insufficient_Beacon_or_Probe_Response_frames",
1778 "Reject-Insufficient_available_capacity_from_all_candidates",
1779 "Reject-BSS_termination_undesired",
1780 "Reject-BSS_termination_delay_requested",
1781 "Reject-STA_BSS_Transition_Candidate_List_provided",
1782 "Reject-No_suitable_BSS_transition_candidates",
1783 "Reject-Leaving_ESS"
1784]
1785
1786
1787class Dot11BSSTMResponse(Packet):
1788 name = "BSS Transition Management Response"
1789 fields_desc = [
1790 ByteField("token", 0),
1791 ByteEnumField("status", 0, btm_status_code),
1792 ByteField("termination_delay", 0),
1793 ConditionalField(
1794 MACField("target", ETHER_ANY),
1795 lambda p: p.status == 0
1796 ),
1797 ConditionalField(
1798 PacketListField(
1799 "neighbor_report",
1800 NeighborReport(),
1801 NeighborReport
1802 ),
1803 lambda p: p.status == 6
1804 )
1805 ]
1806
1807
1808# 802.11-2016 9.6.2.1
1809
1810class Dot11SpectrumManagement(Packet):
1811 name = "802.11 Spectrum Management Action"
1812 fields_desc = [
1813 ByteEnumField("action", 0x00, {
1814 0x00: "Measurement Request",
1815 0x01: "Measurement Report",
1816 0x02: "TPC Request",
1817 0x03: "TPC Report",
1818 0x04: "Channel Switch Announcement",
1819 })
1820 ]
1821
1822
1823# 802.11-2016 9.6.2.6
1824
1825class Dot11CSA(Packet):
1826 name = "Channel Switch Announcement Frame"
1827 fields_desc = [
1828 PacketField("CSA", Dot11EltCSA(), Dot11EltCSA),
1829 ]
1830
1831
1832###################
1833# 802.11 Security #
1834###################
1835
1836# 802.11-2016 12
1837
1838class Dot11Encrypted(Packet):
1839 name = "802.11 Encrypted (unknown algorithm)"
1840 fields_desc = [StrField("data", None)]
1841
1842 @classmethod
1843 def dispatch_hook(cls, _pkt=None, *args, **kargs):
1844 # Extracted from
1845 # https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-ieee80211.c # noqa: E501
1846 KEY_EXTIV = 0x20
1847 EXTIV_LEN = 8
1848 if _pkt and len(_pkt) >= 3:
1849 if (orb(_pkt[3]) & KEY_EXTIV) and (len(_pkt) >= EXTIV_LEN):
1850 if orb(_pkt[1]) == ((orb(_pkt[0]) | 0x20) & 0x7f): # IS_TKIP
1851 return Dot11TKIP
1852 elif orb(_pkt[2]) == 0: # IS_CCMP
1853 return Dot11CCMP
1854 else:
1855 # Unknown encryption algorithm
1856 return Dot11Encrypted
1857 else:
1858 return Dot11WEP
1859 return conf.raw_layer
1860
1861
1862# 802.11-2016 12.3.2
1863
1864class Dot11WEP(Dot11Encrypted):
1865 name = "802.11 WEP packet"
1866 fields_desc = [StrFixedLenField("iv", b"\0\0\0", 3),
1867 ByteField("keyid", 0),
1868 StrField("wepdata", None, remain=4),
1869 IntField("icv", None)]
1870
1871 def decrypt(self, key=None):
1872 if key is None:
1873 key = conf.wepkey
1874 if key and conf.crypto_valid:
1875 d = Cipher(
1876 algorithms.ARC4(self.iv + key.encode("utf8")),
1877 None,
1878 default_backend(),
1879 ).decryptor()
1880 self.add_payload(LLC(d.update(self.wepdata) + d.finalize()))
1881
1882 def post_dissect(self, s):
1883 self.decrypt()
1884
1885 def build_payload(self):
1886 if self.wepdata is None:
1887 return Packet.build_payload(self)
1888 return b""
1889
1890 @crypto_validator
1891 def encrypt(self, p, pay, key=None):
1892 if key is None:
1893 key = conf.wepkey
1894 if key:
1895 if self.icv is None:
1896 pay += struct.pack("<I", crc32(pay) & 0xffffffff)
1897 icv = b""
1898 else:
1899 icv = p[4:8]
1900 e = Cipher(
1901 algorithms.ARC4(self.iv + key.encode("utf8")),
1902 None,
1903 default_backend(),
1904 ).encryptor()
1905 return p[:4] + e.update(pay) + e.finalize() + icv
1906 else:
1907 warning("No WEP key set (conf.wepkey).. strange results expected..") # noqa: E501
1908 return b""
1909
1910 def post_build(self, p, pay):
1911 if self.wepdata is None:
1912 p = self.encrypt(p, raw(pay))
1913 return p
1914
1915# we can't dissect ICV / MIC here: they are encrypted
1916
1917# 802.11-2016 12.5.2.2
1918
1919
1920class Dot11TKIP(Dot11Encrypted):
1921 name = "802.11 TKIP packet"
1922 fields_desc = [
1923 # iv - 4 bytes
1924 ByteField("TSC1", 0),
1925 ByteField("WEPSeed", 0),
1926 ByteField("TSC0", 0),
1927 BitField("key_id", 0, 2), #
1928 BitField("ext_iv", 0, 1), # => LE = reversed order
1929 BitField("res", 0, 5), #
1930 # ext_iv - 4 bytes
1931 ConditionalField(ByteField("TSC2", 0), lambda pkt: pkt.ext_iv),
1932 ConditionalField(ByteField("TSC3", 0), lambda pkt: pkt.ext_iv),
1933 ConditionalField(ByteField("TSC4", 0), lambda pkt: pkt.ext_iv),
1934 ConditionalField(ByteField("TSC5", 0), lambda pkt: pkt.ext_iv),
1935 # data
1936 StrField("data", None),
1937 ]
1938
1939# 802.11-2016 12.5.3.2
1940
1941
1942class Dot11CCMP(Dot11Encrypted):
1943 name = "802.11 CCMP packet"
1944 fields_desc = [
1945 # iv - 8 bytes
1946 ByteField("PN0", 0),
1947 ByteField("PN1", 0),
1948 ByteField("res0", 0),
1949 BitField("key_id", 0, 2), #
1950 BitField("ext_iv", 0, 1), # => LE = reversed order
1951 BitField("res1", 0, 5), #
1952 ByteField("PN2", 0),
1953 ByteField("PN3", 0),
1954 ByteField("PN4", 0),
1955 ByteField("PN5", 0),
1956 # data
1957 StrField("data", None),
1958 ]
1959
1960
1961############
1962# Bindings #
1963############
1964
1965
1966bind_top_down(RadioTap, Dot11FCS, present=2, Flags=16)
1967bind_top_down(Dot11, Dot11QoS, type=2, subtype=0xc)
1968
1969bind_layers(PrismHeader, Dot11,)
1970bind_layers(Dot11, LLC, type=2)
1971bind_layers(Dot11QoS, LLC,)
1972
1973# 802.11-2016 9.2.4.1.3 Type and Subtype subfields
1974bind_layers(Dot11, Dot11AssoReq, subtype=0, type=0)
1975bind_layers(Dot11, Dot11AssoResp, subtype=1, type=0)
1976bind_layers(Dot11, Dot11ReassoReq, subtype=2, type=0)
1977bind_layers(Dot11, Dot11ReassoResp, subtype=3, type=0)
1978bind_layers(Dot11, Dot11ProbeReq, subtype=4, type=0)
1979bind_layers(Dot11, Dot11ProbeResp, subtype=5, type=0)
1980bind_layers(Dot11, Dot11Beacon, subtype=8, type=0)
1981bind_layers(Dot11, Dot11ATIM, subtype=9, type=0)
1982bind_layers(Dot11, Dot11Disas, subtype=10, type=0)
1983bind_layers(Dot11, Dot11Auth, subtype=11, type=0)
1984bind_layers(Dot11, Dot11Deauth, subtype=12, type=0)
1985bind_layers(Dot11, Dot11Action, subtype=13, type=0)
1986bind_layers(Dot11, Dot11Ack, subtype=13, type=1)
1987bind_layers(Dot11Beacon, Dot11Elt,)
1988bind_layers(Dot11AssoReq, Dot11Elt,)
1989bind_layers(Dot11AssoResp, Dot11Elt,)
1990bind_layers(Dot11ReassoReq, Dot11Elt,)
1991bind_layers(Dot11ReassoResp, Dot11Elt,)
1992bind_layers(Dot11ProbeReq, Dot11Elt,)
1993bind_layers(Dot11ProbeResp, Dot11Elt,)
1994bind_layers(Dot11Auth, Dot11Elt,)
1995bind_layers(Dot11Elt, Dot11Elt,)
1996bind_layers(Dot11TKIP, conf.raw_layer)
1997bind_layers(Dot11CCMP, conf.raw_layer)
1998bind_layers(Dot11Action, Dot11SpectrumManagement, category=0x00)
1999bind_layers(Dot11SpectrumManagement, Dot11CSA, action=4)
2000bind_layers(Dot11Action, Dot11WNM, category=0x0A)
2001bind_layers(Dot11WNM, Dot11BSSTMRequest, action=7)
2002bind_layers(Dot11WNM, Dot11BSSTMResponse, action=8)
2003
2004
2005conf.l2types.register(DLT_IEEE802_11, Dot11)
2006conf.l2types.register_num2layer(801, Dot11)
2007conf.l2types.register(DLT_PRISM_HEADER, PrismHeader)
2008conf.l2types.register_num2layer(802, PrismHeader)
2009conf.l2types.register(DLT_IEEE802_11_RADIO, RadioTap)
2010conf.l2types.register_num2layer(803, RadioTap)
2011
2012####################
2013# Other WiFi utils #
2014####################
2015
2016
2017class WiFi_am(AnsweringMachine):
2018 """Before using this, initialize "iffrom" and "ifto" interfaces:
2019iwconfig iffrom mode monitor
2020iwpriv orig_ifto hostapd 1
2021ifconfig ifto up
2022note: if ifto=wlan0ap then orig_ifto=wlan0
2023note: ifto and iffrom must be set on the same channel
2024ex:
2025ifconfig eth1 up
2026iwconfig eth1 mode monitor
2027iwconfig eth1 channel 11
2028iwpriv wlan0 hostapd 1
2029ifconfig wlan0ap up
2030iwconfig wlan0 channel 11
2031iwconfig wlan0 essid dontexist
2032iwconfig wlan0 mode managed
2033"""
2034 function_name = "airpwn"
2035 filter = None
2036
2037 def parse_options(self, iffrom=conf.iface, ifto=conf.iface, replace="",
2038 pattern="", ignorepattern=""):
2039 self.iffrom = iffrom
2040 self.ifto = ifto
2041 self.ptrn = re.compile(pattern.encode())
2042 self.iptrn = re.compile(ignorepattern.encode())
2043 self.replace = replace
2044
2045 def is_request(self, pkt):
2046 if not isinstance(pkt, Dot11):
2047 return 0
2048 if not pkt.FCfield & 1:
2049 return 0
2050 if not pkt.haslayer(TCP):
2051 return 0
2052 tcp = pkt.getlayer(TCP)
2053 pay = raw(tcp.payload)
2054 if not self.ptrn.match(pay):
2055 return 0
2056 if self.iptrn.match(pay) is True:
2057 return 0
2058 return True
2059
2060 def make_reply(self, p):
2061 ip = p.getlayer(IP)
2062 tcp = p.getlayer(TCP)
2063 pay = raw(tcp.payload)
2064 p[IP].underlayer.remove_payload()
2065 p.FCfield = "from-DS"
2066 p.addr1, p.addr2 = p.addr2, p.addr1
2067 p /= IP(src=ip.dst, dst=ip.src)
2068 p /= TCP(sport=tcp.dport, dport=tcp.sport,
2069 seq=tcp.ack, ack=tcp.seq + len(pay),
2070 flags="PA")
2071 q = p.copy()
2072 p /= self.replace
2073 q.ID += 1
2074 q.getlayer(TCP).flags = "RA"
2075 q.getlayer(TCP).seq += len(self.replace)
2076 return [p, q]
2077
2078 def print_reply(self, query, *reply):
2079 p = reply[0][0]
2080 print(p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%"))
2081
2082 def send_reply(self, reply):
2083 sendp(reply, iface=self.ifto, **self.optsend)
2084
2085 def sniff(self):
2086 sniff(iface=self.iffrom, **self.optsniff)
2087
2088
2089conf.stats_dot11_protocols += [Dot11WEP, Dot11Beacon, ]
2090
2091
2092class Dot11PacketList(PacketList):
2093 def __init__(self, res=None, name="Dot11List", stats=None):
2094 if stats is None:
2095 stats = conf.stats_dot11_protocols
2096
2097 PacketList.__init__(self, res, name, stats)
2098
2099 def toEthernet(self):
2100 data = [x[Dot11] for x in self.res if Dot11 in x and x.type == 2]
2101 r2 = []
2102 for p in data:
2103 q = p.copy()
2104 q.unwep()
2105 r2.append(Ether() / q.payload.payload.payload) # Dot11/LLC/SNAP/IP
2106 return PacketList(r2, name="Ether from %s" % self.listname)