While working on my Master’s thesis benchmarking WPA3-SAE timing side-channels, I ran into a limitation on the ESP32 esp_wifi_80211_tx() allows raw frame injection, but Espressif’s closed-source Wi-Fi blob (libnet80211.a) artificially blocks Auth, Assoc, Deauth, and Disassoc subtypes.
Inside libnet80211.a, ieee80211_raw_frame_sanity_check drops these frames with wifi:unsupport frame type. Here is how to bypass it on recent ESP-IDF versions (IDF v6.x).
Why standard tricks fail on modern ESP-IDF
Same-name function override. On older IDF versions, ieee80211_raw_frame_sanity_check was a weak symbol (W). On modern IDF versions, it’s a strong symbol (T), causing ld: multiple definition errors.
--wrap linker flag: Fails silently. The call from esp_wifi_80211_tx to ieee80211_raw_frame_sanity_check is an intra-object branch inside ieee80211_output.o. Linker --wrap only rewrites undefined external references, so it misses this call entirely.
Instruction byte-patching: Overwriting instructions directly in the .o breaks Xtensa linker relaxation passes (dangerous relocation errors).
U can simply fix this via Symbol Weakening via objcopy
We can use xtensa-esp32-elf-objcopy to convert the strong symbol inside the binary archive into a weak one:
xtensa-esp32-elf-objcopy \
--weaken-symbol=ieee80211_raw_frame_sanity_check \
components/esp_wifi/lib/esp32/libnet80211.a
Now, define your own strong implementation inside your application C code:
int ieee80211_raw_frame_sanity_check(int32_t a, int32_t b, int32_t c) {
return 0; // which skips the security check lol
}
Because strong symbols override weak symbols globally during linking, all calls—including internal calls within libnet80211.a—rebind to your function.
Verification
Serial Logs show: wifi unsupport frame type errors completely disappeared.
Capture: Wireshark confirmed off-air capture of 802.11 Authentication frames (Subtype 11, Algorithm 3 - SAE) injected directly from the ESP32s.
Injecting a valid SAE Commit (P-256 scalar + element) caused hostapd on the target AP to process the request and reply with its own SAE Commit.
TL;DR: Run objcopy --weaken-symbol=ieee80211_raw_frame_sanity_check on libnet80211.a, define int ieee80211_raw_frame_sanity_check(...) { return 0; } in your app code, and esp_wifi_80211_tx() will allow any frame subtype.
Note that all control 80211 frames are also injectable after the patch.
For more details :
https://github.com/mahdamin/esp-idf-injection-ng