scapy icon indicating copy to clipboard operation
scapy copied to clipboard

802.11 "FCSField -> cfe" sub-field not in correct place in the FCS field when writing a frame to a file.

Open wfast01 opened this issue 3 years ago • 5 comments

Brief description

In the Dot11 layer, the "FCSField -> cfe" (Control Frame Extension) field occupies bits B12-B15 instead of bits B8-B11 of the FCSField.

Scapy version

2.4.5

Python version

3.8.10

Operating system

Ubuntu 20.04.5 LTS

Additional environment information

No response

How to reproduce

Run the following script to produce the 802.11 frame (python3 -c "import bad_cfe; bad_cfe.bad_cfe()")

bad_cfe

Actual result

pkt.show() prints the following (indicating a cfe = 15 and an FCSField set to 1 (pw-mgt).

bad_cfe_output

However, WireShark indicates that the upper and lower 4 bits of the second byte of the frame have been swapped ("FCS-Field -> cfe" == 1 and bits B12-B15 == 15).

bad_cfe_wireshark

Expected result

Byte 2 of the 802.11 frame (Flags) should be 0x1f (PWR MGT == 1, Control Frame Extension == 15), not 0xf1.

Related resources

See paragraph 9.2.4.1.1 Figure 9-3 in the 802.11 - 2016 specification.

The issue seems to be in the SCAPY Dot11 class. Lines 695 - 698 should moved from their current location and inserted after line 710 to get the field order correct.

bad_cfe_scapy

wfast01 avatar Nov 22 '22 20:11 wfast01

Could you please provide a raw packet or pcap? Thanks

gpotter2 avatar Nov 24 '22 14:11 gpotter2

I have zipped up the pcap file and attached it (the .pcap file type is not supported for uploading, but .zip is supported).
bad_cfe.zip

wfast01 avatar Nov 28 '22 14:11 wfast01

One should tread carefully here. Big Endians and Little Endians are mixed within the IEEE spec for 802.11.

The current way Scapy handles FCS works. There are some quirks, but to touch the FCS for scapy will break a lot of existing code. Please go slow with any changes and test using well known injection tools.

For what its worth, you have not encapsulated your object. It is neither RadioTap() or Ether(). I could be wrong, but I do not think Wireshark handles individual layers of the "packet", rather it must see leading headers to decipher things.

In [9]: pkts[0]
Out[9]: <Dot11  subtype=Control Frame Extension type=Control proto=0 cfe=15 FCfield=pw-mgt ID=0 addr1=10:10:10:10:10:10 (RA) |>

In [10]: pkts[0].show2()
###[ 802.11 ]### 
  subtype   = Control Frame Extension
  type      = Control
  proto     = 0
  cfe       = 15
  FCfield   = pw-mgt
  ID        = 0
  addr1     = 10:10:10:10:10:10 (RA)

When I open that object in Wireshark, Wireshark is confused. I expect this. Again, I could be wrong and would like to see a 2nd pcap where Wireshark correctly parses a single layer?

stryngs avatar Dec 03 '22 06:12 stryngs

Attached is a 2nd pcap file with Dot11() control frames (PS-Poll, RTS, CTS, ...). When Dot11() is used without another encapsulation, the link type in the pcap header is set to LINKTYPE_IEEE802_11 (value 105). WireShark seems to support this link type.

image

ctrl_frms.zip

Per the issue of the position of the Control Frame Extension (cfe) field bits in the FCS for Control Frame Extension frames, I will take a closer look at the spec and also see if I can find some real world examples to work with. The byte order of individual fields seems to be big-endian in the spec and correct in SCAPY - its the ordering of the fields in the SCAPY fields_desc list for the Control Frame Extension case (type 1 subtype 6) that doesn't seem correct. More to follow.

image

wfast01 avatar Dec 05 '22 21:12 wfast01

I didn't catch what you were asking until just now. You mentioned FCS and the lack thereof with Dot11. It does exist however in Dot11FCS.

In [9]: pkts[0]
Out[9]: <Dot11  subtype=PS-Poll type=Control proto=0 FCfield= ID=0 addr1=10:10:10:10:10:10 (RA) addr2=20:20:20:20:20:20 (TA) |>

In [10]: pkts[0].show2()
###[ 802.11 ]### 
  subtype   = PS-Poll
  type      = Control
  proto     = 0
  FCfield   = 
  ID        = 0
  addr1     = 10:10:10:10:10:10 (RA)
  addr2     = 20:20:20:20:20:20 (TA)


In [11]: Dot11FCS().show()
###[ 802.11-FCS ]### 
  subtype   = Association Request
  type      = Management
  proto     = 0
  FCfield   = 
  ID        = 0
  addr1     = 00:00:00:00:00:00 (RA=DA)
  addr2     = 00:00:00:00:00:00 (TA=SA)
  addr3     = 00:00:00:00:00:00 (BSSID/STA)
  SC        = 0
  fcs       = None

It does seem I need to re-readup on how Wireshark handles things. I'd always believed until a couple days ago that Wireshark needed RadioTap or Ether, your example cleanly shows such a thing is not required.

When looking at the pcap I don't see where in Wireshark FCS is mentioned and so I would think scapy correctly chose Dot11 over a Dot11FCS object.

With reference to wifi, there are times when Big Endian and Little Endian exist together in wifi, especially with reference to crc32 outcomes and FCS.

With respect to your thoughts on code being moved, have you tried it? What were the results as far as byte ordering on scapy after say a rdpcap() as opposed to wiresharking it?

stryngs avatar Dec 06 '22 00:12 stryngs