JianrongXiao-Linksys/dnsmasq-cve-2026
GitHub: JianrongXiao-Linksys/dnsmasq-cve-2026
dnsmasq漏洞自动化验证工具
Stars: 0 | Forks: 0
# dnsmasq CVE-2026 QA 验证工具
用于验证 6 个 dnsmasq 漏洞(2026 年 5 月)的自动化黑盒工具。
向实时 DUT 发送攻击数据包并报告 PASS/FAIL — 无需访问源代码。
## 快速开始
```
# 设置 DUT DNS 为笔记本电脑的 WAN IP,首先通过 GUI 进行,然后:
sudo python3 dnsmasq_cve_verify.py --laptop --dut --dut-pass
# 示例:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
```
## 测试的 CVE
| CVE | CVSS | 类型 | 攻击向量 | 受影响功能 |
|-----|------|------|---------------|-----------------|
| CVE-2026-2291 | 9.2 | 堆缓冲区溢出 | 远程 | `extract_name()` — 总是激活 |
| CVE-2026-5172 | 7.5 | OOB 读取 / 崩溃 | 远程 | `extract_addresses()` — 总是激活 |
| CVE-2026-4890 | 7.5 | 无限循环 DoS | 远程 | NSEC 位图解析 (`--dnssec`) |
| CVE-2026-4891 | 5.3 | 堆 OOB 读取 | 远程 | RRSIG 验证 (`--dnssec`) |
| CVE-2026-4892 | 8.4 | 堆溢出 → root | 本地/相邻 | DHCPv6 CLID (`--dhcp-script` + DHCPv6) |
| CVE-2026-4893 | 5.3 | 验证绕过 | 远程 | ECS 源检查 (`--add-subnet`) |
## 每个测试如何工作
### CVE-2026-2291(关键 — extract_name 中的堆溢出)
**根本原因:** `union bigname` 声明 `char name[MAXDNAME]`,但转义字符可以将名称扩展到 `2*MAXDNAME+1` 字节,导致堆溢出。
**测试方法:** 发送包含具有高位字符(0x80+)的域名 DNS 查询,这些域名在内部被 `\DDD` 转义(每输入字节 4 字节)。如果 dnsmasq 崩溃或停止响应,则表示存在漏洞。
**修复后的行为:** 优雅地拒绝过大的名称(FORMERR/REFUSED)或使用扩大的缓冲区。
### CVE-2026-5172(高 — extract_addresses 中的 OOB 读取)
**根本原因:** 伪造的 `rdlen` 字段让 `extract_name()` 指针超出记录末尾。剩余字节数下溢产生巨大值 → 巨大的 OOB 读取 → 崩溃。
**测试方法:** 发送具有 `rdlen` 小于实际编码名称的 CNAME 记录的 DNS 响应。如果 dnsmasq 崩溃,则表示存在漏洞。
**修复后的行为:** 确保 `extract_name()` 之后指针保持在声明的 rdlen 边界内。
### CVE-2026-4890(高 — DNSSEC NSEC 无限循环)
**根本原因:** NSEC 类型位图解析通过 `p[1]` 而不是 `p[1]+2`(缺少窗口头大小)。`bitmap_length=0` 时,指针永远不会前进 → 无限循环。
**测试方法:** 发送具有 `window=0, bitmap_length=0` 的定制 NSEC 记录。如果 dnsmasq 停止响应所有查询(挂起,而不是崩溃),则表示存在漏洞。在 RRSIG 验证之前可利用。
**修复后的行为:** 通过 `p[1]+2` 前进并跳过零长度位图。
### CVE-2026-4891(中 — RRSIG 堆 OOB 读取)
**根本原因:** RRSIG 中的 `rdlen` 未与最小大小(18 + 签名者名称)进行验证。计算的签名长度下溢为负 → 被视为巨大值 → OOB 读取。
**测试方法:** 发送具有 `rdlen=10`(远低于最小 31+ 字节)的 RRSIG 记录。崩溃 = 漏洞。
**修复后的行为:** 在计算签名长度之前验证 `rdlen >= fixed_fields + signer_name_length`。
### CVE-2026-4892(高 — DHCPv6 CLID 本地 root)
**根本原因:** DHCPv6 CLIDs(最多 65535 字节)通过 `sprintf("%.2x")` 转换为 `daemon->packet`(5131 字节)。3000 字节 CLID → 6000 字节十六进制字符串 → 溢出。辅助进程以 root 运行。
**测试方法:** 发送具有 3000 字节客户端标识符的 DHCPv6 SOLICIT。需要 IPv6 相邻性和配置的 `--dhcp-script`。辅助进程崩溃 = 漏洞。
**修复后的行为:** 在十六进制编码之前截断或验证 CLID 长度。
**注意:** 一些构建使用 `-DNO_DHCP6` 编译,不受此 CVE 影响。
### CVE-2026-4893(中 — ECS 源验证绕过)
**根本原因:** `process_reply()` 将 OPT 记录长度(约 23 字节)传递给 `check_source()`,而不是完整的数据包长度。所有边界检查失败 → 函数始终返回 1(有效)。
**测试方法:** 发送包含欺骗源前缀的 EDNS 客户端子网选项的 DNS 查询。如果 dnsmasq 不验证地回显 ECS,则表示存在漏洞。
**修复后的行为:** 将完整数据包长度传递给 `check_source()`,启用根据 RFC 7871 第 9.2 节进行适当的边界检查。
## 补救措施
**升级到 dnsmasq 2.92rel2**(推荐)
- 源:https://thekelleys.org.uk/dnsmasq/dnsmasq-2.92rel2.tar.xz
- 上游补丁:https://thekelleys.org.uk/dnsmasq/CVE/
## 自动化缺陷验证工具 (`dnsmasq_cve_verify.py`)
主要的 QA 工具。在 **测试笔记本电脑** 上运行,向 DUT 发送攻击数据包,
并对每个 CVE 报告清晰的 PASS/FAIL。无需对 DUT 进行任何修改,只需
用于状态检查的只读 SSH 访问。
### 网络拓扑
```
┌─────────────────────────────────────────────────────────────────────┐
│ Testing Laptop │
│ │
│ LAN interface WAN interface │
│ │
│ │ │ │
│ │ ┌────┴──────────────┐ │
│ │ │ Malicious DNS │ │
│ │ │ Server (port 53) │ │
│ │ └────┬──────────────┘ │
│ │ │ │
└────────┼───────────────────────────────┼────────────────────────────┘
│ LAN subnet │ WAN subnet
│ │
┌────────┼───────────────────────────────┼────────────────────────────┐
│ │ │ │
│ LAN: WAN: │
│ (LAN gateway) (WAN uplink) │
│ │
│ DUT (Linksys Router) │
│ dnsmasq (any version < 2.92rel2) │
│ │
│ resolv-file=/etc/resolv.conf │
│ → nameserver ← set via GUI, forwards to us │
│ │
└─────────────────────────────────────────────────────────────────────┘
Data flow:
1. Tool sends DNS query to DUT LAN IP (port 53)
2. DUT's dnsmasq can't resolve locally → forwards upstream to LAPTOP_WAN_IP
3. Our malicious server on WAN interface replies with exploit payload
4. DUT's dnsmasq processes the malicious response → crash/hang/survive
5. Tool checks DUT state via SSH (read-only)
```
**示例设置(您的 IP 地址将不同):**
| 角色 | IP(示例) |
|------|--------------|
| 笔记本电脑 LAN | 192.168.1.254 |
| 笔记本电脑 WAN | 10.0.0.211 |
| DUT LAN | 192.168.1.1 |
| DUT WAN | 10.0.0.214 |
关键要求:**笔记本电脑 WAN IP 和 DUT WAN IP 必须在同一个子网中**,
因此 DUT 可以作为上游 DNS 服务器到达笔记本电脑。
### 它是如何工作的
```
┌──────────┐ ┌───────────┐ ┌──────────────────┐ ┌──────────┐
│ SETUP │ ──► │ TRIGGER │ ──► │ STATE INSPECT │ ──► │ VERDICT │
│ │ │ │ │ │ │ │
│ Start │ │ Send DNS │ │ SSH to DUT: │ │ PASS: │
│ malicious│ │ query to │ │ - pidof dnsmasq │ │ survived │
│ DNS srv │ │ DUT→DUT │ │ - PID changed? │ │ │
│ on WAN │ │ forwards │ │ - dmesg crash? │ │ FAIL: │
│ interface│ │ to us→we │ │ - /var/log/msg │ │ crashed/ │
│ (10.0.0. │ │ reply w/ │ │ │ │ hung │
│ 211:53) │ │ exploit │ │ Liveness query │ │ │
│ │ │ payload │ │ (version.bind) │ │ │
└──────────┘ └───────────┘ └──────────────────┘ └──────────┘
NOTE: Tool does NOT modify DUT settings. User must set DNS to 10.0.0.211 via GUI.
```
### QA 测试程序
#### 先决条件
- 带有两个网络接口的测试笔记本电脑(LAN + WAN)
- Python 3.6+,已安装 `paramiko`(`pip install paramiko`)
- 对 DUT 的 SSH 访问(root 凭证)
- DUT 管理GUI可访问
#### 第 1 步:物理连接
使用两根电缆将测试笔记本电脑连接到 DUT:
| 笔记本电脑端口 | 连接到 | 目的 |
|------------|-------------|---------|
| LAN 端口 | DUT LAN 端口 | SSH 访问 + 向 DUT 发送 DNS 查询 |
| WAN 端口 | DUT WAN 子网(例如,上游交换机/调制解调器端口) | 作为上游 DNS 服务器 |
连接后,注意您的笔记本电脑 IP 地址:
```
# 查找您的 IP
ip addr show | grep "inet "
# 示例输出:
# inet 192.168.1.254/24 ... ← 这是您的 LAN IP
# inet 10.0.0.211/24 ... ← 这是您的 WAN IP(用于 --laptop)
```
#### 第 2 步:通过 GUI 将 DUT DNS 设置为笔记本电脑
1. 打开浏览器并转到 DUT 管理页面:
- 例如,`http://192.168.1.1` 或 `http://myrouter.local`
2. 使用管理员凭据登录
3. 导航到:**连接** → **互联网设置** → **编辑**(位于 IPv4 旁边)
4. 在 **DNS** 下:选择 **静态 DNS**
5. 将 **DNS 1** 设置为您的笔记本电脑的 **WAN IP**(例如,`10.0.0.211`)
6. 点击 **应用**
7. 等待 5-10 秒以使设置生效
#### 第 3 步:运行工具
```
cd /path/to/dnsmasq-cve-2026/
# 运行所有 6 个 CVE 测试:
sudo python3 dnsmasq_cve_verify.py --laptop --dut --dut-pass
# 示例:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
```
该工具将:
1. 通过 SSH 连接到 DUT(只读)
2. 在您的笔记本电脑的 WAN IP 上启动恶意 DNS 服务器
3. 验证 DUT 是否将 DNS 查询转发到它
4. 为每个 CVE 发送漏洞有效载荷
5. 检查 dnsmasq 是否崩溃或挂起
6. 每个 CVE 报告 PASS/FAIL
#### 第 4 步:读取结果
- **PASS** = DUT 安全(功能未激活,或生存了攻击)
- **FAIL** = dnsmasq 崩溃或挂起(漏洞!)
- **ERROR** = 无法连接或 DUT 未转发
#### 第 5 步:恢复 DUT DNS
1. 返回 DUT 管理GUI
2. **连接** → **互联网设置** → **编辑**
3. 在 **DNS** 下:选择 **自动(来自 ISP)** 或删除静态条目
4. 点击 **应用**
#### 故障排除
| 问题 | 解决方案 |
|---------|-----|
| “DUT 未将查询转发给我们” | 验证步骤 2 是否正确完成。检查笔记本电脑 WAN IP 是否与您在 GUI 中输入的匹配。 |
| “无法连接到 DUT” | 验证 SSH 凭证。尝试:`ssh root@192.168.1.1` 手动。 |
| “无法绑定端口 53” | 使用 `sudo` 运行。或者使用 `--dns-port 5353`(需要手动 DUT 配置)。 |
| “版本:未知” | DUT 可能没有在标准路径中安装 dnsmasq。工具仍然可以正确测试。 |
## 测试结果(2026-05-31)
### dnsmasq 2.78 平台(总体:PASS)
| CVE | 结果 | 原因 |
|-----|--------|--------|
| CVE-2026-2291 | PASS | DNSSEC 未编译 |
| CVE-2026-4890 | PASS | DNSSEC 未编译 |
| CVE-2026-4891 | PASS | DNSSEC 未编译 |
| CVE-2026-4892 | PASS | dnsmasq 不提供 DHCPv6(使用单独的 DHCPv6 服务器) |
| CVE-2026-4893 | PASS | 逻辑错误 — 无崩溃 |
| CVE-2026-5172 | PASS | 生存了漏洞(2.78 中的漏洞代码路径不存在) |
### dnsmasq 2.90 平台(总体:PASS)
| CVE | 结果 | 原因 |
|-----|--------|--------|
| CVE-2026-2291 | PASS | DNSSEC 未编译 |
| CVE-2026-4890 | PASS | DNSSEC 未编译 |
| CVE-2026-4891 | PASS | DNSSEC 未编译 |
| CVE-2026-4892 | PASS | DHCPv6 未编译 |
| CVE-2026-4893 | PASS | 逻辑错误 — 无崩溃 |
| CVE-2026-5172 | PASS | 生存了漏洞变体 |
### 结论
所有 Linksys 路由器
标签:逆向工具