Skip to content

Instantly share code, notes, and snippets.

@brainstorm
Last active July 26, 2023 19:18
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save brainstorm/24e843ae0295ee1e41dff47c5b43a02c to your computer and use it in GitHub Desktop.
Save brainstorm/24e843ae0295ee1e41dff47c5b43a02c to your computer and use it in GitHub Desktop.
esp32 promiscuous mode and packet injection experiments
// 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);
}
}
@brainstorm
Copy link
Author

brainstorm commented Dec 13, 2016

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:

� ��a`a=f=pw���������u��uӰ♑}��dComHem0B75C����$0Hl*/0���2`[-���J
@�1P�JDGie[kstL�vO�V3<I7* �     �P���'�BC^b2/F�筆+��c�C�����^૷�/Zx��XR"[@�?/'�u|��%��8Di�bu��k�i�=4.��%�ߐ�1�V�qT/?��z�e]��Q���U���(8���}�wTgl�.%��m�4���M��+�sk-G�K.�لg��gxu�Zۯb>|�O[��a���Ʈ�

000000 C6 20 1F 81 00 00 00 00
000008 00 00 01 C5 61 60 03 00
000010 61 3D 66 3D 00 00 70 77
000018 1F F1 11 00 80 00 00 00
000020 FF FF FF FF FF FF C4 04
000028 15 0B 75 D3 C4 04 15 0B
000030 75 D3 B0 E2 99 91 7D AD
000038 9E 00 00 00 64 00 11 14
000040 00 0C 43 6F 6D 48 65 6D
000048 30 42 37 35 43 46 01 08
000050 82 84 8B 96 24 30 48 6C
000058 03 01 01 05 04 00 01 00
000060 00 2A 01 00 2F 01 00 30
000068 14 01 00 00 0F AC 04 01
000070 00 00 0F AC 04 01 00 00
000078 0F AC 02 0C 00 32 04 0C
000080 12 18 60 0B 05 00 00 5B
000088 00 00 2D 1A BC 19 1B FF
000090 FF 00 00 00 00 00 00 00
000098 00 00 00 00 00 00 00 00
0000A0 00 00 00 00 00 00 3D 16
0000A8 01 08 00 00 00 00 00 00
0000B0 00 00 00 00 00 00 00 00
0000B8 00 00 00 00 00 00 4A 0E
0000C0 14 00 0A 00 2C 01 C8 00
0000C8 14 00 05 00 19 00 7F 08
0000D0 05 00 08 00 00 00 00 40
0000D8 DD 31 00 50 F2 04 10 4A
0000E0 00 01 10 10 44 00 01 02
0000E8 10 47 00 10 69 06 65 5B
0000F0 6B 73 74 4C E8 AB 76 4F
0000F8 1C 88 56 33 10 3C 00 01
000000 03 10 49 00 06 00 37 2A
000008 00 01 20 DD 09 00 10 18
000010 02 00 00 0C 00 00 DD 18
000018 00 50 F2 02 01 01 84 00
000020 03 A4 00 00 27 A4 00 00
000028 42 43 5E 00 62 32 2F 00
000030 46 05 72 08 01 00 00 00
000038 B6 E7 AD 86 2B B2 04 DB
000040 63 D5 43 8E BA 99 A3 B4
000048 5E E0 AB B7 B9 2F 5A 78
000050 A2 F3 04 08 CC 58 52 22
000058 5B 40 87 3F 2F 27 C7 14
000060 12 75 7C A4 9A 25 C3 FE
000068 0E 38 44 69 C1 62 75 02
000070 13 8B F3 6B 9C 69 D4 3D
000078 34 2E D7 DD 25 AE DF 90
000080 1D C9 31 CE 56 89 71 0B
000088 54 2F 3F B8 86 7A 95 65
000090 AA B1 43 68 A0 27 3E E9
000098 93 7F BA B5 65 A3 A7 39
0000A0 7C 66 A9 2C C2 83 E7 76
0000A8 E2 85 60 C9 39 D2 3A A0
0000B0 76 3F 34 AD F5 08 C2 00
0000B8 CB 4D BF F0 2B 82 73 6B
0000C0 2D 47 F8 9E 4B 2E C0 94
0000C8 D9 84 67 D2 E6 67 78 75
0000D0 F8 5A DB 0F AF 62 3E 7C
0000D8 9D 17 4F 5B E4 F7 B8 61
0000E0 97 10 88 FE C6 AE 16 A4
0000E8 0D 65 5D EF 19 EA 51 F5
0000F0 D9 17 C9 55 03 CF F6 D4
0000F8 28 38 9E E4 FB 7D 8F 77
000000 54 67 6C B7 2E 25 EA BE
000008 FA 6D 1F AA 01 00 1F 01

/ping @chris-zen

@brainstorm
Copy link
Author

As a cross-reference with the discussion in the ESP32.com forum about this topic:

http://esp32.com/viewtopic.php?f=2&t=580&start=10

@brainstorm
Copy link
Author

The approach above will never inject 802.11 frames, reversing of libpp.a and lib80211.a seems to be needed:

http://esp32.com/viewtopic.php?p=3053#p3053

@nissimzur
Copy link

Hi brainstorm,
Can I hire you to small work on esp32 promiscuous?
Please email me to nissim@vitelix.com or call my Skype nissim.text
Thank you
-Nissim

@dsiganos
Copy link

dsiganos commented Jun 17, 2017

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

@Staubgeborener
Copy link

Staubgeborener commented Jun 24, 2017

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]);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment