wifi嗅探者,便宜又简单

· 7min · Juicecat
Table of Contents

# 介绍

WiFi背后的物理学

WiFi嗅探器与WiFi本身一样长。这个概念很简单 - 想象您在黑暗中有一个灯笼。它在周围的360度半径上闪耀光,其附近的任何人都可以看到光线。现在,想象一下,灯笼发出的光是无形的,可以通过固体物体:这正是WiFi信号,尽管太过简化了。

实际上,WiFi信号是电磁辐射(EMR)的一种形式,与光,X射线甚至热灯相同。它的频率相对较低,可以使其渗透固体对象,否则,如果您和接入点之间有墙壁,则无法连接到WiFi。

1

## 概念

由于信息通过这些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

这就是输出的外观 - 1

# 结论

正如一开始所述,这只是一个POC,并且在任何实用的方式中都非常有用。已经建立了为此目的而建立的奇妙工具,例如WiresharkAir*-ng suite

这篇文章的目的是简化解释和概述WiFi嗅探是什么,以及它可以实现的容易。因此,我希望我能够很好地解释我不太擅长写博客文章,但我正在尝试改进,所以请忍受我。