DF-1400 / wi_overflow.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 | /* * DF-1400 harness: wi_write_wep LUCENT WEP-key stack overflow. * * Replicates the EXACT vulnerable logic from: * sys/dev/netif/wi/if_wi.c:1751-1769 (LUCENT branch) * struct wi_key wkey[IEEE80211_WEP_NKID]; // wkey[4] on the stack * ... * keylen = vap->iv_nw_keys[i].wk_keylen; // up to IEEE80211_KEYBUF_SIZE=16 * wkey[i].wi_keylen = htole16(keylen); * memcpy(wkey[i].wi_keydat, vap->iv_nw_keys[i].wk_key, keylen); // SINK * * Struct layout verbatim from sys/dev/netif/wi/if_wavelan_ieee.h:290-292: * struct wi_key { * u_int16_t wi_keylen; * u_int8_t wi_keydat[14]; // <-- 14-byte destination * }; * IEEE80211_KEYBUF_SIZE = 16 (sys/netproto/802_11/ieee80211_crypto.h:34) * IEEE80211_WEP_NKID = 4 (sys/netproto/802_11/ieee80211.h:1272) * * keylen can be 15 or 16 (the WEP cipher accepts >=5 with no upper bound; the * ioctl path bounds by IEEE80211_KEYBUF_SIZE=16). memcpy of 16 bytes into the * 14-byte wi_keydat overflows by 1-2 bytes. For i==3 (the last wkey slot) the * overflow runs off the wkey[4] array and into the surrounding stack frame. * * The QEMU guest has no Prism/Lucent WiFi hardware, so wi(4) never attaches and * wi_write_wep is unreachable live here. This harness proves the primitive * deterministically with the exact struct layout. * * Build: cc -O2 -o wi_overflow wi_overflow.c * Run: ./wi_overflow */ #include <stdio.h> #include <string.h> #include <stdint.h> #define IEEE80211_KEYBUF_SIZE 16 #define IEEE80211_WEP_NKID 4 /* if_wavelan_ieee.h:290-292 */ struct wi_key { uint16_t wi_keylen; uint8_t wi_keydat[14]; }; int main(void) { /* Mirror the kernel stack layout: wkey[4] followed by a canary region. */ struct { struct wi_key wkey[IEEE80211_WEP_NKID]; uint8_t frame_canary[16]; } s; uint8_t wk_key[IEEE80211_KEYBUF_SIZE]; int keylen = IEEE80211_KEYBUF_SIZE; /* 16, the max the ioctl path allows */ memset(&s, 0, sizeof(s)); memset(s.frame_canary, 0xCC, sizeof(s.frame_canary)); /* canary after wkey[4] */ memset(wk_key, 0xAB, sizeof(wk_key)); /* attacker key material */ printf("DF-1400 wi_write_wep (LUCENT) primitive demonstration\n"); printf("wi_key.wi_keydat capacity: %zu bytes\n", sizeof(s.wkey[0].wi_keydat)); printf("keylen (wk_keylen, up to IEEE80211_KEYBUF_SIZE): %d\n", keylen); int overflow_slots = 0; for (int i = 0; i < IEEE80211_WEP_NKID; i++) { /* ---- exact kernel logic (if_wi.c:1766-1769) ---- */ s.wkey[i].wi_keylen = (uint16_t)keylen; memcpy(s.wkey[i].wi_keydat, wk_key, keylen); /* SINK */ } /* Examine each slot's damage. */ for (int i = 0; i < IEEE80211_WEP_NKID; i++) { /* Bytes beyond wi_keydat[14] for this slot: into the next wi_key's * wi_keylen (or, for i==3, off the array into the frame). */ unsigned char *after = (unsigned char*)&s.wkey[i].wi_keydat[14]; int hit = 0; for (int b = 0; b < keylen - 14; b++) if (after[b] != 0) hit = 1; printf("slot %d: wrote %d bytes into 14-byte wi_keydat -> %d byte(s) past end%s\n", i, keylen, keylen - 14, (i == IEEE80211_WEP_NKID - 1) ? " [runs OFF the wkey[4] array into the frame]" : ""); if (hit) overflow_slots++; } /* i==3 (last slot): overflow lands in the frame canary. */ int frame_hit = 0; for (size_t b = 0; b < sizeof(s.frame_canary); b++) if (s.frame_canary[b] != 0xCC) { frame_hit = 1; break; } printf("frame region after wkey[4] corrupted by last slot: %s\n", frame_hit ? "YES" : "no"); if (keylen > (int)sizeof(s.wkey[0].wi_keydat) && overflow_slots > 0) { printf("\nOVERFLOW CONFIRMED: keylen=%d > wi_keydat[14] overflows by %d byte(s) per slot; " "last slot overruns wkey[4] into the stack frame.\n", keylen, keylen - 14); printf("On real Prism/Lucent WiFi HW (state transition AUTH/RUN) this is a stack " "overflow in wi_write_wep -> corruption/panic.\n"); return 0; } fprintf(stderr, "ERROR: overflow not observed\n"); return 1; } |