b2uerry/tl-wr902ac-cve-2026
GitHub: b2uerry/tl-wr902ac-cve-2026
该项目披露了 TP-Link TL-WR902AC 路由器 RADIUS 认证模块因使用未播种的 random() 导致认证符可预测的高危漏洞(CWE-338),并提供了完整的 PoC 与修复方案。
Stars: 0 | Forks: 0
# CVE 提交包
# TP-Link TL-WR902AC v4 - rt2860apd 中的 CWE-338
## 1. 漏洞概述
**标题:** 由于未播种的 `random()` 导致 rt2860apd 中的 RADIUS Authenticator 可预测
**CWE:** CWE-338 - 使用密码学上较弱的伪随机数生成器 (PRNG)
**产品:** TP-Link TL-WR902AC v4 (旅行路由器)
**受影响固件:** EU_0.9.3_0.3 (2025-08-21 构建,发布版本 43848)
- 二进制文件:/usr/bin/rt2860apd (Ralink DOT1X daemon,版本 2.6.0.0)
- 固件 MD5:84d5acf2f429fa8868d80f7723bfe70b
- 二进制文件链接库:uClibc 0.9.33.2
**严重性:** 高 (CVSS 3.1: 7.5)
- 攻击向量:网络 (邻接)
- 攻击复杂度:低
- 所需权限:无
- 用户交互:无
- 影响范围:未改变
- 机密性影响:高 (绕过认证)
- 完整性影响:高 (伪造 RADIUS 消息)
**发现者:** b2uerry
**发现日期:** 2026-06-24
## 2. 技术描述
### 2.1 受影响组件
`rt2860apd` 是 Ralink/MediaTek WiFi Access Point daemon,负责:
- 802.1X/WPA2-Enterprise 认证
- RADIUS 客户端通信
- WPA 密钥握手 (4-way handshake)
该二进制文件为 MIPS32 little-endian 编译,并动态链接到 uClibc 0.9.33.2。
### 2.2 根本原因
位于地址 `0x406e8c` 的函数 `Radius_msg_make_authenticator` 通过以下计算生成 RADIUS Request Authenticator 字段:
```
int Radius_msg_make_authenticator(RADIUS_MSG *msg, void *station, int len) {
struct timeval tv;
int rand_val;
gettimeofday(&tv, NULL); // 0x406e9c
rand_val = random(); // 0x406eb0
MD5_Init(&ctx); // 0x406eb8
MD5_Update(&ctx, &tv, 8); // 0x406ec4
MD5_Update(&ctx, station, 4); // 0x406ed0
MD5_Update(&ctx, &rand_val, 4); // 0x406edc
MD5_Final(msg->authenticator, &ctx); // 0x406ef0
}
```
因此,该 authenticator 为:
```
MD5( tv_sec || tv_usec || station_data[0:4] || random() )
```
### 2.3 为什么存在漏洞
对 rt2860apd 的完整二进制审计显示:
1. **从未调用 `srandom()`。** 符号 `srandom` 既没有导入,也没有出现在 PLT 中。完整的交叉引用搜索结果为零。
2. **根据 C 标准和 glibc 的行为**,在没有预先调用 `srandom()` 的情况下调用 `random()` 时,PRNG 默认 seed = 1。所有输出 100% 是确定性的。
3. **`gettimeofday()` 提供了微秒精度**,但是根据数据包捕获时间戳,`tv_sec` 的值可以在几秒钟内被预测。
4. **同一二进制文件中的其他函数使用了 `hostapd_get_rand()`** (该函数从 `/dev/urandom` 读取),但 `Radius_msg_make_authenticator` 并未使用。
### 2.4 攻击场景
同一网段上的攻击者可以:
1. 捕获设备发送的 RADIUS Access-Request 数据包
2. 提取 16 字节的 Authenticator 字段
3. 知道 (或猜测) `station_data` 的 4 字节值
4. 估算数据包时间戳 (相对于 pcap 时间 ±2 秒)
5. 为每个候选秒数暴力破解 `tv_usec` (0-999,999)
6. 为每个候选值计算 `MD5(tv || station_data || 0x6b8b4567)`
7. 与捕获的 authenticator 进行匹配
每秒不确定性的搜索空间为 2,000,000 个 MD5 哈希,在单个 CPU 核心上大约 1.3 秒即可完成。
**影响:** 攻击者可以预测下一个 RADIUS authenticator,从而能够:
- 伪造 RADIUS 消息
- 绕过 802.1X 认证
- 未经授权访问网络
## 3. 概念验证
PoC 以附加包中的 `final_proof.py` 形式提供。
它演示了:
### 证明 1:`random()` 的确定性
```
$ python3 final_proof.py
random() seed=1, 3 independent resets:
[0] = 1804289383 (0x6b8b4567) ← identical across all resets
[1] = 846930886 (0x327b23c6)
[2] = 1681692777 (0x643c9869)
...
```
### 证明 2:Authenticator 预测测试向量
提供了四个测试向量以供独立验证。
示例:
```
Input: tv_sec=0x60000000, tv_usec=0x00000000, station=0x00000000
random()=0x6B8B4567 (deterministic, seed=1)
Output: MD5 = 06691441de1006440050152c8fcbf00d
```
### 证明 3:暴力破解可行性
```
Target authenticator: 0f850ee3cdce057898d426ebdd694a4c
±1 second search: 1,500,001 MD5 candidates
Time to match: 1.08 seconds
Result: EXACT MATCH (tv_sec=1782286400, tv_usec=500000)
```
### 证明 4:跨架构验证
MIPS (QEMU 用户模式) 和 x86 (本地) 的 `random()` 产生相同的输出:
```
MIPS: [1804289383, 846930886, 1681692777, 1714636915, 1957747793]
x86: [1804289383, 846930886, 1681692777, 1714636915, 1957747793]
```
glibc 和设备使用的 uClibc 0.9.33.2 都为 `random()` 实现了相同的 BSD libc TYPE_3 多项式。依赖 seed 的输出与架构无关。
## 4. 补救措施
将对 `random()` 的调用替换为密码学安全的源:
```
// Vulnerable:
rand_val = random();
// Fixed:
hostapd_get_rand(&rand_val, sizeof(rand_val));
// (hostapd_get_rand already exists in the binary at 0x407400
// and reads from /dev/urandom)
```
注意:同一二进制文件中的 `ieee802_1x_tx_key()` 和 `Config_read()` 已经使用了 `hostapd_get_rand()`,这证实了该修复是最小化且非侵入性的。
## 5. 披露时间线
- 2026-06-22:在固件分析中发现漏洞
- 2026-06-24:PoC 开发并验证完成 (3/3 独立证明)
- 2026-06-24:请求 CVE / 通知供应商
- 待定: 供应商回复
## 6. 参考资料
- CWE-338: https://cwe.mitre.org/data/definitions/338.html
- RFC 2865 - RADIUS: https://datatracker.ietf.org/doc/html/rfc2865
- IEEE 802.1X-2010 - Port-Based Network Access Control
标签:CVE, IoT安全, 密码学缺陷, 数字签名, 漏洞披露, 路由器漏洞, 身份验证强制, 逆向分析, 逆向工具, 防御绕过