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