Sniffers WiFi, bon marché et facile
Introduction
La physique derrière le wifi
Les renifleurs WiFi existent aussi longtemps que le WiFi lui-même. Le concept est simple - imaginez que vous avez une lanterne dans l'obscurité. Il brille la lumière dans un rayon à 360 degrés autour de lui, et toute personne à proximité pourra voir la lumière. Maintenant, imaginez que la lumière émise par la lanterne est invisible et peut passer par des objets solides: c'est exactement ce que sont les signaux WiFi, bien qu'immensément simplifié.
En effet, les signaux WiFi sont une forme de rayonnement électromagnétique (DME), identique à la lumière, aux rayons X et même aux lampes chauffantes. Sa fréquence relativement basse lui permet de imprégner des objets solides, sinon vous ne pourriez pas vous connecter à votre wifi s'il y a un mur entre vous et le point d'accès.
Concept
Parce que les informations sont échangées via ces signaux WiFi, cela pose un intérêt pour des acteurs malveillants potentiels ou simplement des individus curieux. Avec du matériel couramment disponible et une connaissance minimale du sujet, il est possible de capturer et d'enregistrer tous les signaux WiFi qui se trouvent à proximité - et c'est ce que nous allons explorer aujourd'hui.
Préparation
Matériaux
Pour faire de notre sniffer wifi, nous n'avons besoin que d'un ordinateur qui peut accéder au WiFi et a un adaptateur capable d'entrer en mode promiscuité. Dans mon last post, j'ai introduit le "mini ordinateur" SOC ESP32 par EspressIF. Ce sont extraordinairement bon marché, petits et puissants. Vous pouvez acheter un here pour environ 7 $ USD.
Logiciel
Afin d'écrire le renifleur, nous utiliserons la chaîne d'outils esp-idf (refer to this post to see why). J'utilise le VScode IDE comme éditeur de texte, mais ce que vous utilisez est une préférence personnelle et ne fait aucune différence.
Écriture du code
Le code de ce projet est très simple et juste un POC, il est donc minime et non utile. Dans les projets ESP-IDF, nous commençons par un point d'entrée dans notre fonction app_main()
. Avant de faire quoi que ce soit, nous devons faire quelques étapes de configuration préalable afin d'initialiser les méthodes WiFi et de rappel:
- Démarrez la boucle d'événement ESP32
- Initialiser NVS Flash
- Initialiser l'interface réseau
- Configurer l'interface réseau
Étapes 1 et 2
Ces étapes sont très simples et assez standard pour les projets de ce type - voici le code, que je vais expliquer ci-dessous. N'oubliez pas que tout cela est contenu dans notre fonction de point d'entrée.
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
L'étape 1 est entièrement contenue dans une seule ligne de code sur la ligne 1- Le reste initialise le Flash NVS. Il y a une vérification conditionnelle ici qui, en cas d'erreur, efface la mémoire flash et essaie de l'initialiser à nouveau. La fonction ESP_ERROR_CHECK()
que vous voyez tout au long de cet extrait est une fonction intégrée qui accepte un code de retour et lance une erreur si le code de retour est autre chose que le succès.
Étapes 3 et 4
Maintenant que nous sommes prêts à utiliser l'ESP32, nous devons configurer les composants du réseau. J'ai extrait ces étapes dans une fonction distincte, qui est juste appelée de la fonction principale afin d'organiser un peu mieux le code:
static void setup_wifi(void) {
// Initializ
ESP_LOGI(TAG, "Beginning wifi setup");
ESP_ERROR_CHECK(esp_netif_init());
// Interface defaults
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
// Default config
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
// Setup callback
wifi_promiscuous_cb_t callback = &wifi_callback;
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(callback));
// Set station mode and start
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
// Config filters and stuff
wifi_promiscuous_filter_t filter = {.filter_mask =
WIFI_PROMIS_FILTER_MASK_MGMT};
esp_wifi_set_promiscuous_filter(&filter);
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
ESP_LOGI(TAG, "Wifi started successfully");
wifi_mode_t ptr;
ESP_ERROR_CHECK(esp_wifi_get_mode(&ptr));
const char *c = wifi_mode_to_string(ptr);
ESP_LOGI(TAG, "Mode: %s", c);
}
Afin d'utiliser réellement ces paquets, nous devons créer une fonction de rappel, qui est appelée chaque fois qu'un cadre correspondant au filtre est capturé, ce que nous faisons sur la ligne 15-16.
Sur la ligne 23, j'ai défini un filtre pour ne capturer que des cadres de gestion, ce qui est juste un certain type de message - je le fais sans autre raison que pour réduire le bruit créé par ce programme, sinon il y aurait des milliers de paquets par seconde en frappant l'interface. Ce code est assez explicite, mais vous remarquerez peut-être que j'appelle une fonction appelée wifi_mode_to_string
. En effet
const char *wifi_mode_to_string(wifi_mode_t mode) {
switch (mode) {
case WIFI_MODE_NULL:
return "WIFI_MODE_NULL";
case WIFI_MODE_STA:
return "WIFI_MODE_STA";
case WIFI_MODE_AP:
return "WIFI_MODE_AP";
case WIFI_MODE_APSTA:
return "WIFI_MODE_APSTA";
case WIFI_MODE_NAN:
return "WIFI_MODE_NAN";
case WIFI_MODE_MAX:
return "WIFI_MODE_MAX";
default:
return "UNKNOWN_MODE";
}
}
met tout ensemble
Maintenant, tout est configuré, nous avons juste besoin de créer la fonction de rappel WiFi et les données de journal que nous obtenons. Dans notre fonction de rappel, comme il s'agit d'un POC, nous n'avons pas besoin de faire autre chose que d'imprimer les cadres
void wifi_callback(void *buf, wifi_promiscuous_pkt_type_t type) {
const uint16_t data_length = 256;
ESP_LOGI(TAG, "Printing first %d bytes of received packet with type %s\n",
data_length, wifi_pkt_type_to_string(type));
unsigned char *char_buf = (unsigned char *)buf;
for (int i = 0; i < data_length; i++) {
printf("%02X ", char_buf[i]); // 1 byte = 0x00, two hex chars
if (i % 16 == 15) { // Organize it by groups of 16 bytes because im spoiled by wireshark
printf("\n");
}
}
}
Exécution
Maintenant, nous naviguons simplement vers le répertoire de travail du projet et construisons le projet, le compilons, le flasis sur l'ESP32 et établissons enfin une connexion UART afin que nous puissions voir la sortie. Nous pouvons le faire avec une commande simple:
idfx build && idfx flash COM11 monitor
Et voici à quoi ressemble la sortie
Conclusion
Comme indiqué au début, ce n'est qu'un POC, et est pas utile vraiment de manière pratique. Il existe des outils établis et fantastiques déjà conçus à cet effet, tels que Wireshark et Air*-ng suite.
Le but de cet article est de fournir une explication simplifiée et un aperçu de ce qu'est le reniflement WiFi et de la facilité avec laquelle il peut être accompli. En tant que tel, j'espère que j'ai pu expliquer bien les choses, je ne suis pas génial pour écrire des articles de blog, mais j'essaie d'améliorer, alors veuillez supporter avec moi.