wifi嗅探者,便宜又简单
Table of Contents
# 介绍
WiFi背后的物理学
WiFi嗅探器与WiFi本身一样长。这个概念很简单 - 想象您在黑暗中有一个灯笼。它在周围的360度半径上闪耀光,其附近的任何人都可以看到光线。现在,想象一下,灯笼发出的光是无形的,可以通过固体物体:这正是WiFi信号,尽管太过简化了。
实际上,WiFi信号是电磁辐射(EMR)的一种形式,与光,X射线甚至热灯相同。它的频率相对较低,可以使其渗透固体对象,否则,如果您和接入点之间有墙壁,则无法连接到WiFi。
## 概念
由于信息通过这些WiFi信号交换,因此这对潜在的恶意演员或简单的好奇个人产生了兴趣。有了常见的硬件和对该主题的最低知识,可以捕获和记录附近的任何WiFi信号 - 这就是我们今天要探索的。
# 准备
## 材料
为了制作我们的WiFi嗅探器,我们只需要一台可以访问WiFi并具有能够输入滥交模式的适配器的计算机。在我的last post中,我介绍了Espressif的“迷你计算机” SOC ESP32。这些非常便宜,小而有力。您可以以约7美元的价格购买一个here。
## 软件
为了编写嗅探器,我们将使用esp-idf工具链(refer to this post to see why)。我使用VSCODE IDE作为我的文本编辑器,但是您使用的编辑器是个人喜好,没有区别。
#编写代码
该项目的代码非常简单,只是POC,因此它很小,没有那么有用。在ESP-IDF项目中,我们从app_main()
函数的入口点开始。在进行任何事情之前,我们需要执行一些先决条件步骤,以便初始化WiFi和回调方法:
1。启动ESP32事件循环
2。初始化NVS Flash
3。初始化网络接口
4。配置网络接口
###步骤1&2
这些步骤对于此类型的项目非常简单,非常标准 - 这是代码,我将在下面解释。请记住,这全都包含在我们的入口点函数中。
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);
步骤1完全包含在第1行上的一行代码中 - 其余的正在初始化NVS闪存。这里有一个条件检查,如果发生错误,则会删除闪存并尝试再次初始化它。您在此片段中看到的ESP_ERROR_CHECK()
函数是一个内置函数,它接受返回代码,如果返回代码是成功之外的任何东西,则会引发错误。
###步骤3&4
现在我们准备使用ESP32,我们需要设置网络组件。我将这些步骤提取到一个单独的函数中,该功能刚刚从主函数中调用,以便更好地组织代码:
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);
}
为了实际使用这些数据包,我们需要创建一个回调函数,每当捕获过滤器匹配的框架时,我们就会在第15-16行中进行调用。
在第23行上,我将过滤器设置为仅捕获管理框架,这只是某种消息 - 除了减少该程序创造的噪声之外,我无缘无故地这样做,否则每秒会有成千上万的数据包命中接口。此代码是相当自我解释的,但是您可能会注意到我称之为称为wifi_mode_to_string
的函数。这是因为wifi_mode_t
成员是枚举,并且出色的C语言无法打印出枚举的字符串表示形式,因此我们必须手动映射它:
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";
}
}
###将它们放在一起
现在所有内容都是设置,我们只需要创建我们获得的WiFi回调函数和日志数据即可。在我们的回调函数中,由于这是一个POC,因此除了打印帧 -
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");
}
}
}
###执行
现在,我们只需导航到项目工作目录并构建项目,将其编译,将其刷新到ESP32,最后建立一个UART连接,以便我们可以看到输出。我们可以使用一个简单的命令来完成此操作:
idfx build && idfx flash COM11 monitor
这就是输出的外观 -
# 结论
正如一开始所述,这只是一个POC,并且在任何实用的方式中都非常有用。已经建立了为此目的而建立的奇妙工具,例如Wireshark和Air*-ng suite。
这篇文章的目的是简化解释和概述WiFi嗅探是什么,以及它可以实现的容易。因此,我希望我能够很好地解释我不太擅长写博客文章,但我正在尝试改进,所以请忍受我。