-
-
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
0x25
and repeated shortly afterwards (src
/dst
MAC 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