-
-
Save brainstorm/24e843ae0295ee1e41dff47c5b43a02c to your computer and use it in GitHub Desktop.
| // Espressif ESP32 promiscuous mode and packet injection experiments | |
| // by brainstorm at nopcode org | |
| #include "freertos/FreeRTOS.h" | |
| #include "esp_wifi.h" | |
| #include "esp_wifi_internal.h" | |
| #include "lwip/err.h" | |
| #include "esp_system.h" | |
| #include "esp_event.h" | |
| #include "esp_event_loop.h" | |
| #include "nvs_flash.h" | |
| #include "driver/gpio.h" | |
| uint8_t HEX_COLSIZE = 7; | |
| esp_err_t event_handler(void *ctx, system_event_t *event) | |
| { | |
| return ESP_OK; | |
| } | |
| void process_promisc(void* buf, uint16_t len) | |
| { | |
| char* buflen = (char*) buf + len; | |
| uint8_t hexdump_cols = 0; | |
| uint8_t offset = 0; | |
| // RAW packet | |
| for (char* ptr = buf; ptr < buflen; ptr++) printf("%c", *ptr); | |
| printf("\n\n"); | |
| // Hexdump (wireshark-friendly) | |
| for (char* ptr = buf; ptr < buflen; ptr+=HEX_COLSIZE) { | |
| // print offset | |
| printf(" %06X ", offset); | |
| for (hexdump_cols=0; hexdump_cols < HEX_COLSIZE; hexdump_cols++) | |
| printf(" %02X", *(ptr+hexdump_cols*sizeof(char))); | |
| offset = offset + HEX_COLSIZE; | |
| printf("\n"); | |
| } | |
| printf("\n\n"); | |
| } | |
| void send_packet(esp_interface_t iface, void* buf, uint8_t len) | |
| { | |
| printf("Sending actual packet via driver...\n"); | |
| switch(esp_wifi_internal_tx(iface, buf, len)) | |
| { | |
| case ERR_OK: | |
| printf("Packet in the air!\n"); | |
| break; | |
| case ERR_IF: | |
| printf("WiFi driver error\n"); | |
| break; | |
| default: | |
| printf("Some other error I don't want to control now\n"); | |
| break; | |
| } | |
| } | |
| void app_main(void) | |
| { | |
| wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); | |
| esp_interface_t wifi_if; | |
| void* wifi_eth = NULL; | |
| nvs_flash_init(); | |
| tcpip_adapter_init(); | |
| ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); | |
| printf("Setting up wifi\n"); | |
| ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); | |
| ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); | |
| ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); | |
| //printf("Promiscuous mode callback\n"); | |
| //esp_wifi_set_promiscuous(true); | |
| //esp_wifi_set_promiscuous_rx_cb(&process_promisc); | |
| ESP_ERROR_CHECK( esp_wifi_start() ); | |
| // Borrowed from the original esp8266 injection example: | |
| // https://github.com/kripthor/WiFiBeaconJam/blob/master/WiFiBeaconJam.ino | |
| uint8_t packet[128] = { 0x80, 0x00, 0x00, 0x00, | |
| /*4*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
| /*10*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, | |
| /*16*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, | |
| /*22*/ 0xc0, 0x6c, | |
| /*24*/ 0x83, 0x51, 0xf7, 0x8f, 0x0f, 0x00, 0x00, 0x00, | |
| /*32*/ 0x64, 0x00, | |
| /*34*/ 0x01, 0x04, | |
| /* SSID */ | |
| /*36*/ 0x00, 0x06, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, | |
| 0x01, 0x08, 0x82, 0x84, | |
| 0x8b, 0x96, 0x24, 0x30, 0x48, 0x6c, 0x03, 0x01, | |
| /*56*/ 0x04}; | |
| wifi_if = tcpip_adapter_get_esp_if(wifi_eth); | |
| printf("About to send packets every 200ms\n"); | |
| while(true) | |
| { | |
| send_packet(wifi_if, (void*)packet, sizeof(packet)); | |
| vTaskDelay(200 / portTICK_RATE_MS); | |
| } | |
| } |
As a cross-reference with the discussion in the ESP32.com forum about this topic:
The approach above will never inject 802.11 frames, reversing of libpp.a and lib80211.a seems to be needed:
Hi brainstorm,
Can I hire you to small work on esp32 promiscuous?
Please email me to [email protected] or call my Skype nissim.text
Thank you
-Nissim
It appears that Espressif will be imminently releasing a feature to inject 802.11 data frames (but not management frames):
https://esp32.com/viewtopic.php?f=13&t=2025#p9539
It is probably the function esp_wifi_80211_tx() introduced by this commit:
espressif/esp32-wifi-lib@ce0ce8b
Another approach is to get the whole frame by casting the buffer and greb the playload with casted_buffer->payload. Also the length is in sig_len (see https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_wifi_types.h). With this variant, i'll also get nearly all of the packets. Though i also have the same problem with malformed packets.
a possibility could be:
// get length of packet
for (i = 0; i < casted_buffer->rx_ctrl.sig_len; i++) {
// print payload
printf(" %02X", casted_buffer->payload[i]);
}
This gist originated after playing with the ESP32 promiscuous callback and while searching around the esp32.com community forums.
Below there's a dump from the callback function in the code outlined above. The mac address can be found on offset
0x25and repeated shortly afterwards (src/dstMAC addresses):C4 04 15 0B 75 D3.The rest of the payload resembles a 802.11 WLAN/Ethernet frame, but wireshark still has some issues decoding it when imported as a plain hexfile:
/ping @chris-zen