Tianfu Cup 2021 RT-AX56U RCE
2021 年天府杯目标之一是 ASUS RT-AX56U V2,比赛要求选手从 LAN 侧未授权获取设备 root shell,在比赛开始前 ASUS 官方发布了数个补丁来修复漏洞,但依然有两队选手成功破解了此设备,本文将对其中涉及的相关漏洞进行分析。
firmware
固件可从 ASUS 官方网站 下载,我们以 RT-AX56U V1 设备的 3.0.0.4.386.42808 为例进行分析。
下载固件后 binwalk 可直接解包,得到一个标准的 Linux 文件系统,从 /usr/sbin 目录下找到关键文件 cfg_server
环境准备
为了方便分析,首先要打开设备的 ssh 服务,导航到设备后台 -> 系统管理 -> 系统设置 -> 启用 SSH,来开启 ssh 服务。
通过管理员账户连接 ssh,在 /tmp/test 目录下准备一个 gdbserver(链接:https://pan.baidu.com/s/1Z_1EBswZWWIX-AU6joIh_Q 提取码:4ypa), 可利用设备的 wget 命令从外部服务器下载到本地。
漏洞分析
cfg_server 二进制程序同时监听 tcp 与 udp 的 7788 端口,它实现了 WiFI Mesh 的相关功能。
基本数据处理流程
用 IDA 逆向分析此程序,通过 recv 函数交叉引用,可以找到名为 cm_tcpPacketHandler 的函数,读取数据部分:
1 | while ( 1 ) |
这里调用 read_tcp_message 函数读取外部输入,然后调用 cm_packetProcess 函数处理数据。
cm_packetProcess 逻辑较多,简单来讲,此函数希望收到符合 TLV 格式的数据,所谓 TLV 即 标识域(Tag)+ 长度域(Length)+ 值域(Value),cfg_server 对数据格式定义比较简单:
1 | 0 8 16 24 32 (bit) |
程序会根据 opcode 来调用不同的 handler 函数,TCP 和 UDP 端口分别对应一些 handler。
1 | TCP |
处理数据时,先获取 opcode 字段,根据 opcode 调用不同的函数,将 data_len、data_crc、data 作为第 4、5、7 个参数传入。
整数溢出 -> 堆溢出
相同的漏洞点位多个函数中,以其中之一为例。当 opcode = 0x2a 时,程序调用 cm_processACK_GROUPID 函数,代码片段 1
1 | //... |
第 4 行转换 data_len 字节序,第 7 行调用 crc32 函数计算 data 部分的 CRC 值,要求得到的值和 data_crc 相同。第 16 行调用 cm_aesDecryptMsg 函数尝试解密数据。
代码片段2
1 | //... |
cm_aesDecryptMsg 函数会调用 aes_decrypt 函数。
代码片段3
1 | v17[0] = 0; |
此函数使用 openssl 库中的 aes256 部分,前几行初始化 EVP_CIPHER_CTX 结构体,第 13 行将 data_len 和 EVP_CIPHER_CTX_block_size(CTX) 值相加,调试可知这里的 EVP_CIPHER_CTX_block_size(CTX) = 0x10。
第 14 行通过相加得到的值分配内存空间,第 25 行调用 EVP_DecryptUpdate 函数开始对数据进行循环解密,循环次数等于 data_len。
问题在于,整个解密流程中,程序没有对 data_len(unsigned int) 变量进行校验,当我们传递一个较大的值,例如 0xffffffff,第 13 行相加操作产生整数溢出,v11 是 unsigned int 类型,整数溢出后它会变成一个较小的值,导致 malloc 分配很小的内存空间。而后续解密数据时循环次数使用了 data_len,将拷贝过多数据到堆内存空间,造成堆溢出。
Mesh 配对流程分析
能够触发堆溢出的途径很多,我们选择其中较为完整的分析,尝试理解 cfg_server 配对流程。
1. 请求公钥
客户端收到配对消息,构造 opcode = 1 的请求,cfg_server 调用 cm_processREQ_KU 函数,此函数直接返回保存在内存中的一个 rsa_publickey。
伪造客户端请求数据:
1 | 0 8 16 24 32 (bit) |
2. 交换密钥
客户端收到 public key,构造 opcode = 3 的请求,cfg_server 调用 cm_processREQ_NC 函数,此函数实现了简单的密钥交换功能。
伪造客户端请求数据:
1 | 0 8 16 24 32 (bit) |
part1_data 为客户端指定的一个 AES256 密钥,part2_data 为客户端 nonce 值。
客户端将以上数据利用之前请求得到的公钥进行加密,然后发送到服务端,服务端收到请求后进行多个校验,如果全部通过,服务端会构造响应报文
1 | 0 8 16 24 32 (bit) |
返回的数据中 data 部分利用客户端提供的 AES 密钥进行了加密,客户端自行解密后得到数据
1 | 0 8 16 24 32 (bit) |
关键内容是 server_nonce。
3. 握手
客户端收到服务端返回的 server_nonce 后,通过以下算法得到此次会话的 session_key
1 | sha256("A22AAC3EB69F9943ED8929D810A077A3" + server_nonce + client_nonce) |
之后客户端构造 opcode = 5 的请求,cfg_server 调用 cm_processREP_OK 函数,服务端按照相同的逻辑计算出 session_key。
伪造客户端请求数据:
1 | 0 8 16 24 32 (bit) |
如果服务端返回 0x6 开头的响应,说明握手成功,服务端把会话的 session_key 放到一个全局变量:clientHashTable 中,后续只要客户端不切断连接,就可以用这个 session_key 调用更多功能。
4. 触发漏洞
客户端构造 opcode = 0xf 的请求,cfg_server 调用 cm_processREQ_JOIN 函数,此函数尝试将具有合法会话的客户端加入 mesh 列表。
部分代码如下
1 | //... |
这里就回到前面的漏洞分析部分,AES 解密时 len 使用不当,所以我们可以构造如下请求触发漏洞
1 | 0 8 16 24 32 (bit) |
由于 data_len 异常,所以 crc 校验只需传入 data_crc = 0 即可绕过。此外,payload 部分应使用 session_key 进行 AES 加密。
利用分析
此漏洞是堆溢出,按照正常思路应该收集程序中可能的 malloc 和 free 流程,然后通过如 fastbin_attack 等手段完成利用,但经过调试分析发现,当堆块布局满足一定条件时,openssl 初始化的 EVP_CIPHER_CTX 结构体将位于堆溢出内存下方,这就意味着可修改此结构体中的一些成员变量。
这里提供一种思路,查看 openssl 源代码 可以看到 EVP_CIPHER_CTX 的具体定义
1 | struct evp_cipher_ctx_st { |
第一个成员也是结构体,定义如下
1 | struct evp_cipher_st { |
我们发现此结构体后面几个变量都是函数指针,其中第 8 个成员会在 EVP_CIPHER_CTX_reset 函数中被使用
1 | int __fastcall EVP_CIPHER_CTX_reset(_DWORD *evp_cipher_st) |
如果我们通过堆溢出能够将 EVP_CIPHER_CTX 中第一个成员指针劫持到一可控内存,就能劫持程序的控制流。
样例利用过程
首先完成上述握手流程,在握手流程期间程序会多次调用 malloc、free 等函数,heap 有较大变化,一定情况下将形成以下布局
1 | +--------+--------+--------+--------+ |
EVP_CIPHER_CTX 结构体相距用户可控输入距离为 0x30 字节。
初始内存布局:
1 | 0xb64009f8: 0x00000000 0x00000000 0x00000000 0x00000000 |
我们构造数据,刚好覆盖掉 EVP_CIPHER_CTX 第一个成员变量,使 0xb6400a28 = 0xb64009f8,0xb6400a14 = system@plt,0xb6400a2c = `reboot`
构造后内存布局:
1 | 0xb64009f8: 0x00000000 0x00000000 0x00000000 0x00000000 |
在 libcrypto.so.1.1 中的 EVP_CIPHER_CTX_reset 函数下断点,当执行到调用函数指针时程序状态:
此时就能执行我们设置的命令。
样例调试程序
调试脚本(非 EXP)如下,感兴趣的话可以自行调试分析。
1 | from pwn import * |
PS:cm_processACK_GROUPID 功能中的 AES 解密密钥从 get_onboarding_key 函数而来,可通过调试获取。
最后
此服务所在程序只能从内网访问,所以危害有限。
利用此漏洞需要一些特殊的内存布局,感兴趣的读者可自行尝试其它更稳定的利用手段。
如文章有误敬请指正,欢迎来信讨论。
- Title: Tianfu Cup 2021 RT-AX56U RCE
- Author: Catalpa
- Created at : 2021-11-02 00:00:00
- Updated at : 2024-10-17 08:55:36
- Link: https://wzt.ac.cn/2021/11/02/TFC2021-AX56U/
- License: This work is licensed under CC BY-NC-SA 4.0.