如何使用 NL80211_BSS_CAPABILITY 获取扫描网络的 WiFi 安全密钥(WPA、WPA2、ESS)?

How to get WiFi security key(WPA, WPA2, ESS) of scanned networks using NL80211_BSS_CAPABILITY?

我正在使用 netlink 库 nl80211.h 扫描 wifi 网络并成功获取 ssid、mac 地址、状态、频率和信号。我想使用相同的库添加每个网络的安全类型。 我使用 NL80211_BSS_CAPABILITY 作为枚举之一,它是一个整数,为了安全起见,我将其硬编码到我的代码中。这似乎很乏味,并且必须使用这种方法提供大量数据(整数值)。获取 WPA/WPA2 很好,但是当周围有开放网络时代码会失败。以下是我到目前为止使用的值。一个更好的逻辑可以让我打开网络(ESS 或 WEP),最好类似于 wpa_supplicant 和 netlink 库。

int keynum;
char *keytype;
keynum = nla_get_u32(bss[NL80211_BSS_CAPABILITY]);

if(keynum==5153 || keynum == 34)
    keytype="NONE";

else if(keynum==5169 || keynum == 1297 || keynum==1073|| keynum == 5393)
    keytype="WPA2";

else if (keynum == 1041)
    keytype="WPA WPA2";

else
    keytype="WPA WPA2";

首先我们来看一下NL80211_BSS_CAPABILITY
中有什么样的数据 为了理解这一点,我将首先提请您注意 属性 NL80211_BSS_BEACON_IES
该字段说明如下:

/**
* @NL80211_BSS_BEACON_IES: binary attribute containing the raw
* information
*/

source
但我认为这样的描述太笼统了,更详细的描述,我们转here.
首先,我们感兴趣的是:

  1. Capability Information (2 byte) This field contains number of subfields that are used to indicate requested or advertised optional capabilities.

例如,使用 wireshark 捕获的一个数据包及其 Сapabilities Information 字段(一篇关于如何做到这一点的好文章是 here):

Сapabilities Information: 0x0431
            .... .... .... ...1 = ESS capabilities: Transmitter is an AP
            .... .... .... ..0. = IBSS status: Transmitter belongs to a BSS
            .... ..0. .... 00.. = CFP participation capabilities: No point coordinator at AP (0x00)
            .... .... ...1 .... = Privacy: AP/STA can support WEP
            .... .... ..1. .... = Short Preamble: Allowed
            .... .... .0.. .... = PBCC: Not Allowed
            .... .... 0... .... = Channel Agility: Not in use
            .... ...0 .... .... = Spectrum Management: Not Implemented
            .... .1.. .... .... = Short Slot Time: In use
            .... 0... .... .... = Automatic Power Save Delivery: Not Implemented
            ...0 .... .... .... = Radio Measurement: Not Implemented
            ..0. .... .... .... = DSSS-OFDM: Not Allowed
            .0.. .... .... .... = Delayed Block Ack: Not Implemented
            0... .... .... .... = Immediate Block Ack: Not Implemented

正如我们所观察到的,其中一个标志(在通用名称 security 下,或在本例中为 Privacy: AP/STA can support WEP)。这个标志,正如所写的那样,告诉我们这个网络支持 wep 加密。但是,该标签的其他标志不携带有关网络使用的其他编码算法的信息。因此,随后,对该字段的分析将变为:

if (bss[NL80211_BSS_CAPABILITY] != NULL) {
    wlan_info.bss_capability = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
  }
  if (!(wlan_info.bss_wpa1_wpa2 | wlan_info.bss_wpa2 | wlan_info.bss_wpa1)) {
    wlan_info.bss_wep = wlan_info.bss_capability & 16;
  }

但这还没有结束。我们还需要查找其他加密算法的资料。
为此,我们回到 NL80211_BSS_BEACON_IES.
1.We检查是否为空

if (NULL != bss[NL80211_BSS_BEACON_IES] && NULL != nla_data(bss[NL80211_BSS_BEACON_IES]))

2.We遍历每一个标签,读取前两个字节,从上面的文章中可以看出,我们从而找出了标签的类型和包含的数据长度.

for (int i = 0;;) {
      bool first = i;
      uint8_t header_type =
          *(uint8_t *)((nla_data(bss[NL80211_BSS_BEACON_IES])) + i++);
      uint8_t header_len =
          *(uint8_t *)((nla_data(bss[NL80211_BSS_BEACON_IES])) + i++);
      i += header_len;

3.Among 我们正在寻找 2 个特定标签的所有标签:# 48 (0x30)# 221 (0xDD)。它们可能看起来像这样:

第一个:

Tag: RSN Information
            Tag Number: RSN Information (48)
            Tag length: 20
            RSN Version: 1
            Group Cipher Suite: 00:0f:ac (Ieee 802.11) AES (CCM)
                Group Cipher Suite OUI: 00:0f:ac (Ieee 802.11)
                Group Cipher Suite type: AES (CCM) (4)
            Pairwise Cipher Suite Count: 1
            Pairwise Cipher Suite List 00:0f:ac (Ieee 802.11) AES (CCM)
                Pairwise Cipher Suite: 00:0f:ac (Ieee 802.11) AES (CCM)
                    Pairwise Cipher Suite OUI: 00:0f:ac (Ieee 802.11)
                    Pairwise Cipher Suite type: AES (CCM) (4)
            Auth Key Management (AKM) Suite Count: 1
            Auth Key Management (AKM) List 00:0f:ac (Ieee 802.11) PSK
                Auth Key Management (AKM) Suite: 00:0f:ac (Ieee 802.11) PSK
                    Auth Key Management (AKM) OUI: 00:0f:ac (Ieee 802.11)
                    Auth Key Management (AKM) type: PSK (2)
            RSN Capabilities: 0x0000

在 RSN 信息标签中,我们对 2 个字段(未来 4 个字节)感兴趣:Auth Key Management (AKM) OUI: 00: 0f: ac (Ieee 802.11)Auth Key Management (AKM) type: PSK (2).

取决于 (AKM) type: PSK (2)(AKM) type: WPA (1) 这些将分别是 WPA2WPA1

第二个:

Tag: Vendor Specific: Microsoft Corp.: WPA Information Element
            Tag Number: Vendor Specific (221)
            Tag length: 22
            OUI: 00:50:f2 (Microsoft Corp.)
            Vendor Specific OUI Type: 1
            Type: WPA Information Element (0x01)
            WPA Version: 1
            Multicast Cipher Suite: 00:50:f2 (Microsoft Corp.) AES (CCM)
                Multicast Cipher Suite OUI: 00:50:f2 (Microsoft Corp.)
                Multicast Cipher Suite type: AES (CCM) (4)
            Unicast Cipher Suite Count: 1
            Unicast Cipher Suite List 00:50:f2 (Microsoft Corp.) AES (CCM)
                Unicast Cipher Suite: 00:50:f2 (Microsoft Corp.) AES (CCM)
                    Unicast Cipher Suite OUI: 00:50:f2 (Microsoft Corp.)
                    Unicast Cipher Suite type: AES (CCM) (4)
            Auth Key Management (AKM) Suite Count: 1
            Auth Key Management (AKM) List 00:50:f2 (Microsoft Corp.) PSK
                Auth Key Management (AKM) Suite: 00:50:f2 (Microsoft Corp.) PSK
                    Auth Key Management (AKM) OUI: 00:50:f2 (Microsoft Corp.)
                    Auth Key Management (AKM) type: PSK (2)

这个指向我们WPA1 WPA2。这是我们如何处理它的片段。

if (header_type == VENDOR_TAG_ID) {
        long long int oui = 0;
        memcpy(&oui,
               (uint8_t *)((nla_data(bss[NL80211_BSS_BEACON_IES])) -
                           header_len + i),
               6);
        if (oui == WPA1_WPA2_BEACON) wlan_info.bss_wpa1_wpa2 = 1;
      } else if (header_type == RSN_TAG_ID) {
        int32_t oui = 0;
        memcpy(&oui,
               (uint8_t *)((nla_data(bss[NL80211_BSS_BEACON_IES])) - 6 + i), 4);
        if ((oui == WPA2_BEACON_1) || (oui == WPA2_BEACON_2))
          wlan_info.bss_wpa2 = 1;
        else if (oui == WPA1_BEACON)
          wlan_info.bss_wpa1 = 1;
      }

这里使用的定义是:

#define RSN_TAG_ID 0x30
#define VENDOR_TAG_ID 0xdd
#define BEACON_DATA_LEN 0x100
#define BSS_SSID_LEN BEACON_DATA_LEN
#define WPA1_BEACON 0x1AC0F00
#define WPA2_BEACON_1 0x2AC0F00
#define WPA2_BEACON_2 0x4AC0F00
#define WPA1_WPA2_BEACON 0x101F25000

另一个有趣的点是iw kernel impl
Look here 这是一个现成的功能,但我没有研究过它是如何工作的。

void print_ies(unsigned char *ie, int ielen, bool unknown,
           enum print_ie_type ptype)
{
    struct print_ies_data ie_buffer = {
        .ie = ie,
        .ielen = ielen };

    if (ie == NULL || ielen < 0)
        return;

    while (ielen >= 2 && ielen - 2 >= ie[1]) {
        if (ie[0] < ARRAY_SIZE(ieprinters) &&
            ieprinters[ie[0]].name &&
            ieprinters[ie[0]].flags & BIT(ptype)) {
            print_ie(&ieprinters[ie[0]],
                 ie[0], ie[1], ie + 2, &ie_buffer);
        } else if (ie[0] == 221 /* vendor */) {
            print_vendor(ie[1], ie + 2, unknown, ptype);
        } else if (ie[0] == 255 /* extension */) {
            print_extension(ie[1], ie + 2, unknown, ptype);
        } else if (unknown) {
            int i;

            printf("\tUnknown IE (%d):", ie[0]);
            for (i=0; i<ie[1]; i++)
                printf(" %.2x", ie[2+i]);
            printf("\n");
        }
        ielen -= ie[1] + 2;
        ie += ie[1] + 2;
    }
}

最后一点是“组”“attr”的属性。与应用于 wiphy structures
的“组”属性“bss”不同 我还没有对此进行足够的研究以了解网络管理员如何从中提取有关网络的必要信息,但是您可以尝试查看 linblnetlink 来源,并且可能会有相关信息。这里还有一个如何使用它们的例子:
repo
source file
安全密钥的枚举值:

/**
 * NMDeviceWifiCapabilities:
 * @NM_WIFI_DEVICE_CAP_NONE: device has no encryption/authentication capabilities
 * @NM_WIFI_DEVICE_CAP_CIPHER_WEP40: device supports 40/64-bit WEP encryption
 * @NM_WIFI_DEVICE_CAP_CIPHER_WEP104: device supports 104/128-bit WEP encryption
 * @NM_WIFI_DEVICE_CAP_CIPHER_TKIP: device supports TKIP encryption
 * @NM_WIFI_DEVICE_CAP_CIPHER_CCMP: device supports AES/CCMP encryption
 * @NM_WIFI_DEVICE_CAP_WPA: device supports WPA1 authentication
 * @NM_WIFI_DEVICE_CAP_RSN: device supports WPA2/RSN authentication
 * @NM_WIFI_DEVICE_CAP_AP: device supports Access Point mode
 *
 * 802.11 specific device encryption and authentication capabilities.
 **/
typedef enum {
    NM_WIFI_DEVICE_CAP_NONE          = 0x00000000,
    NM_WIFI_DEVICE_CAP_CIPHER_WEP40  = 0x00000001,
    NM_WIFI_DEVICE_CAP_CIPHER_WEP104 = 0x00000002,
    NM_WIFI_DEVICE_CAP_CIPHER_TKIP   = 0x00000004,
    NM_WIFI_DEVICE_CAP_CIPHER_CCMP   = 0x00000008,
    NM_WIFI_DEVICE_CAP_WPA           = 0x00000010,
    NM_WIFI_DEVICE_CAP_RSN           = 0x00000020,
    NM_WIFI_DEVICE_CAP_AP            = 0x00000040
} NMDeviceWifiCapabilities;

以及使用方法:
source file

if (tb[NL80211_ATTR_CIPHER_SUITES]) {
    int num;
    int i;
    __u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]);

    num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof(__u32);
    for (i = 0; i < num; i++) {
        switch (ciphers[i]) {
        case 0x000fac01:
            info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40;
            break;
        case 0x000fac05:
            info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP104;
            break;
        case 0x000fac02:
            info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP |
                      NM_WIFI_DEVICE_CAP_WPA;
            break;
        case 0x000fac04:
            info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP |
                      NM_WIFI_DEVICE_CAP_RSN;
            break;
        default:
            nm_log_err (LOGD_HW | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITES %#8.8x.", ciphers[i]);
            break;
        }
    }
}

以及那里使用的调用和回调“链”:

     wifi_utils_init (const char *iface, int ifindex, gboolean check_scan)
                                  ^
                                  ||
             wifi_nl80211_init (const char *iface, int ifindex)
                                   ^
                                  ||
    static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)

WPA 3 编辑:
我还不能说什么。我的搜索从 this page 开始,然后继续搜索 link.
的页面 nmcli 可能不支持 WPA 3 自上次提交以来,根据存储库判断,是 9 年前(并且 WPA 3 是由 802.11ax standard如果我没记错的话,就在两年前。
如果您有一个使用 WPA 3 加密的接入点,可以使用命令 nmcli dev wifi 轻松检查。 与 nmcli 不同,iw 存储库中的最后一次提交相对较新,因此,它可能已经在处理我们的案例。
另外,我不能说来自 wireshark 加密 WPA 3 的数据包的内容,因为我没有必要的访问点,因此我没有测试它。