一个字符,让 DNS 沉默
清华团队在 DNS 里发现了一类"静默漏洞"——不是报错,是不回话。它让 18 年前的防御模型重新失效。但这场争论,比论文本身更值得看。
一、先说结论
2026 年 9 月,Pwnie Awards 把"最具创新研究奖"颁给了一篇论文:
One Char to Rule Them All: Systematically Exploring and Exploiting DNS Silent Vulnerabilities in Domain Name Resolution
作者是清华网络研究院的苗发生、李想、安常青、王继龙,联合奇虎 360 网络空间测绘中心。论文发在 IEEE S&P 2026,讲在 Black Hat Asia 2026,配套的另一篇(RebirthDay)发在 ACM CCS 2025。
它做的事:发现主流 DNS 软件在处理"特殊字符"时,会选择沉默——不发 NXDOMAIN,不发 SERVFAIL,什么都不发。
为什么这很严重:DNS 缓存投毒的本质是"跟时间赛跑"。沉默取消了赛跑——解析器等不到合法响应,超时从 100 毫秒变成 5 秒。攻击窗口扩大了 50 倍。
二、问题从四十年前埋起
DNS 诞生于 1983 年。它的字符集规范,有两份文件在打架:
RFC 1035(1987):
域名只能包含字母、数字、连字符。
RFC 2181(1997):
实现"must not place any restrictions on label content"(不得对标签内容施加任何限制)。
任何二进制串都可以作为标签。
两份都对,但在不同层面:
- RFC 1035 是"怎么用"——为了保证互操作性
- RFC 2181 是"能存什么"——为了协议通用性
结果是:实现者必须自己选一个。
于是我们看到:
| 实现 | 选择 |
|---|---|
| BIND / Unbound / Microsoft DNS | 全部接受(65 个特殊字符) |
| Technitium DNS | 只接受 3 个,拒绝 62 个 |
| MaraDNS | 接受 32 个,拒绝 33 个 |
| ChromeOS | 只接受 1 个 |
四十年了,没有人系统测过"DNS 到底支持哪些字符"。
论文做了这件事——用 {char}.{nonce}.attacker.com 的格式,把 0x00 到 0x7F 全部 ASCII 字符都试了一遍。
三、最扎眼的一列
测试结果表里有一列叫 "Support 响应"——意思是"对支持的字符,你回不回包"。
BIND 支持 65 个字符 → ✕ 不回
Unbound 支持 65 个字符 → ✕ 不回
Microsoft 支持 65 个字符 → ✕ 不回
Windows 支持 65 个字符 → ✕ 不回
macOS 支持 65 个字符 → ✕ 不回
iOS 支持 65 个字符 → ✕ 不回
Android 支持 65 个字符 → ✕ 不回
Linux 支持 65 个字符 → ✓ 回 NXDOMAIN
翻译成人话:
"我接受这个字符,但我不回答关于它的查询。"
只有 Linux 的 stub resolver 做对了——它回 NXDOMAIN,告诉调用者"这域名不存在"。
其余四大操作系统(Windows / macOS / iOS / Android)全部沉默。
这意味着什么:你在 iPhone 上打开任何 App,如果它去解析一个含特殊字符的域名,getaddrinfo() 会一直阻塞,直到系统 DNS 超时。你不知道为什么,因为没人告诉你。
四、攻击怎么打
论文把它命名为 SHAR 攻击(PPT 里写的是 Shar = Special Characters),一个漏洞,四种打法:
Attack-1(VEN):给老攻击加个暂停键
DNS 缓存投毒靠"抢跑":
T=0ms 攻击者发查询
T=1ms 解析器问权威 NS
T=2ms 攻击者狂发伪造响应(猜 32 位 TxID+端口)
T=50ms 真实 NS 回应 ← 谁先到信谁
SHAR 做的事:让真实 NS 闭嘴。
T=0ms 攻击者发 {特殊字符}.evil.com
T=1ms 解析器问权威 NS
T=2ms ★ 权威 NS 收到畸形查询 → 静默丢弃
T=2ms~5s ★ 解析器干等(5 秒超时)
攻击者从容伪造
论文的结论:增强了 13 种经典 off-path 投毒攻击中的 10 种。
Attack-2(VBF):让"不可行"重新可行
这是全文最狠的一段。
DNS 抗投毒的全部防线 = 16 位 TxID + 16 位端口 = 32 位
2008 年之后:窗口只有 80-100ms → 暴力破解"理论可行但实际不划算"
SHAR 之后:窗口拉到 5000ms → 扩大 50 倍
论文数据:20 次试验,20 次全部成功。
而且标注了:"这个攻击自 2008 年起一直被认为不可行"。
Attack-3 / 4(VLB / VSF):打健康检查
递归解析器会"按响应速度给 NS 排优先级"。SHAR 用一个字符让某台 NS 永远沉默,解析器就把它降级:
- VLB:把流量全压到剩下的 NS → 单点过载
- VSF:让所有 NS 都沉默 → 解析器直接返回
SERVFAIL→ 域名彻底解析不了
这比传统 DDoS 更狠:不需要流量,只需要一个特殊字符的查询。绕过所有流量层防护。
五、影响面
| 对象 | 结果 |
|---|---|
| 主流 DNS 软件 | 31 / 31 |
| Wi-Fi 路由器 | 21 / 21 |
| 路由操作系统 | 6 / 6 |
| 公共 DNS 服务 | 43 / 43 |
| 开放 DNS 解析器 | 531,100(60.1%) |
| TLD | 522(36.1%) |
| 域名 | 1,250 万(5.6%) |
路由器名单:360、ASUS、Cisco、D-Link、Fast、Fiberhome、H3C、Honor、Huawei、iKuai、Linksys、Mercury、Netgear。
全中,没有一个例外。
六、然后是争议
如果博客到这里结束,它是篇软文。
因为 dnsmasq 的维护者 David Conrad 在披露后的回应,值得完整引用:
你似乎重新发现了 1993 年就讨论过的 DNS 事务 ID 缺陷。
据我所知,这与"特殊字符"无关——域名里不存在特殊字符(见 RFC 2181 第 11 节)。Hostname 是域名的子集,确实有字符限制,但这不应(RFC 2119 里的 MUST NOT)影响解析。
如果上游解析器静默丢弃这些查询,那是那些解析器的 bug。
这个协议缺陷存在于所有 DNS 解析器实现中,这正是 DNSSEC 被发明的原因。
dnsmasq 转发任意 QNAME 是正确的做法。 处理被丢弃的查询/响应是所有解析器都必须做的事——尤其考虑到 DNS 主要用 UDP。
这个问题的正确缓解措施是开启 DNSSEC。
这段话的分量,不亚于论文本身。
拆开看,Conrad 提出了三个反驳:
反驳一:这不是新问题
1993 年就有过 TxID 缺陷的讨论(他给了 Purdue 的论文链接)。Kaminsky 2008 只是让它重新进入公众视野。
反驳二:"特殊字符"这个概念不成立
RFC 2181 §11 明确说:DNS 协议层面不存在"非法字符"。所谓的"特殊字符",是应用层(hostname)的限制,不是 DNS 的限制。
换句话说:BIND 沉默不是因为"字符非法",是因为它选择了丢弃畸形报文——而这是允许的。
反驳三:错的是解析器,不是协议
"如果上游解析器静默丢弃这些查询,那是那些解析器的 bug。"
这句话直接把论文的"根因"从"RFC 矛盾"挪到了"实现缺陷"。
七、那这篇论文到底改变了什么
我认为 Conrad 说得对的地方,恰恰不是论文的弱点。
两边说的不是同一件事:
| 论文在说 | Conrad 在说 | |
|---|---|---|
| 层面 | 测量 + 工程现实 | 规范 + 设计意图 |
| 主张 | "真实世界里,31 个实现全部静默" | "规范上,它们不该静默" |
| 结论 | 攻击可行 | 应该改实现 + 上 DNSSEC |
两个都成立。
论文的价值不在"发现了新协议缺陷" —— 它没有。TxID 缺陷是 1993 年的,"静默丢弃"是 RFC 允许的。
论文的价值在"测量":
它第一次证明:在真实世界里,31 个主流实现、21 台家用路由器、43 个公共 DNS 服务、53 万个开放解析器,全部选择了"沉默"这个最危险的行为。
这是一份"现实清单",不是"理论突破"。
而清单本身就有杀伤力——因为它意味着:
- DNSSEC 部署率还不够(Conrad 自己也说这是正解)
- 2008 年之后的 32 位随机化,是"用熵换时间"——一旦时间被拉长,熵就不够了
- "沉默"是所有实现的默认选择,而默认值决定了大多数人的安全水平
八、配套论文:RebirthDay
同一课题组(李想、苗发生等)在 ACM CCS 2025 发了另一篇:RebirthDay Attack: Reviving DNS Cache Poisoning with the Birthday Paradox。
它复活的是 2002 年就被认为"已死"的生日悖论攻击。
核心机制:利用 ECS(EDNS Client Subnet) 一致性检查的缺失或错误实现,绕过旨在阻止生日攻击的查询聚合机制。
影响(据公开披露):22 款主流 DNS 软件中 18 款受影响,波及 16 家路由器厂商、14 个公共 DNS 服务、36.5 万个开放解析器(约 15%),已分配 50 个 CVE(如 BIND9 的 CVE-2025-40776、Unbound 的 CVE-2025-5994)。
两篇合起来看,才有意思:
| 解决什么 | 用的是什么 | |
|---|---|---|
| RebirthDay | 32 位空间太大 | 生日悖论(降低复杂度) |
| SHAR / VBF | 100ms 窗口太短 | 静默(拉长到 5s) |
一个攻"空间",一个攻"时间"。
Kaminsky 之后建立的防御模型,在这两个维度上同时被拆。
这才是"18 年平衡被打破"的准确含义——被打破的不是 32 位随机化本身,而是"攻击窗口始终很短"这个隐含假设。
九、我的判断
论文的强项
① 问了一个太基础、基础到没人问的问题
DNS 被研究了 43 年:缓存投毒有 DNSSEC,放大攻击有 BCP38,隐私有 DoH/DoT。
但"这个协议到底允许哪些字符",没人系统测过。
② 测量做到了全链路
不是只看"解析器",是从 stub resolver 到权威服务器,四个角色全部覆盖。31 个软件 + 21 台路由器 + 43 个公共 DNS + 53 万开放解析器。
③ "静默"这个词抓得准
它不制造错误,它制造空白——而空白在协议里等于时间,时间等于攻击窗口。
错误可以被捕获和修正,空白只会被时间填满。
论文的弱点
① "根因"的定性可能过强
论文把根因归到"RFC 1034 与 RFC 2181 矛盾"。但 Conrad 的反驳直接命中:这两个 RFC 说的不是同一层的事(一个是 hostname 语法,一个是 DNS 标签的通用性)。
"矛盾"更像是"分工",不是"bug"。
② 对"静默是 bug"的论证不够
如果所有实现都认为"丢弃畸形报文是合理行为"(RFC 允许),那"静默"就不是漏洞,是规范内的选择。
论文没有回应这个反驳——至少 PPT 里没有。
③ VEN 的"增强 10/13"缺少对照
"增强"的具体量化(成功率从多少提升到多少)PPT 没给。这可能是论文里有、但演讲略过,也可能是本来就模糊。
真正值得记住的三件事
① DNSSEC 不是"可选项"
Conrad 说得直白:"正确的缓解措施是开启 DNSSEC"。
32 位随机化是"用熵换时间"——时间一变,熵就不够。只有密码学签名不依赖时间。
② 默认值决定了安全水平
所有实现的默认动作都是"沉默丢弃"。没有一个是"明确报错"。
这不是设计失误,是"最小惊讶原则"的副作用——"不介入"看起来最安全,实际上最危险。
③ 基础研究的分量,不在攻击,在测量
这篇论文没有发明新攻击。 VEN 是给老攻击加 buff,VBF 是让老攻击重新可行。
但它第一次量化了"现实有多糟"。
而"现实有多糟"这件事,比"理论上能打"重要得多——因为防御要修的是现实,不是理论。
十、给运维的建议
如果你的网络里有 DNS 服务:
立刻做的:
- 开启 DNSSEC 验证(Conrad 的原话)
- 检查路由器固件——21/21 全中,包括 360、华为、荣耀、H3C、水星、爱快
- 自建 AdGuard Home / Pi-hole 的,检查上游是否静默——它们都在受影响名单里
值得做的:
- 开启 0x20 编码(域名大小写随机化,增加熵)
- 限制开放递归(53 万开放解析器是攻击的基础设施)
- 监控"解析超时"——静默的表现是超时,不是错误。超时率异常升高,可能就是有人在试
长期:
- 别指望"统一实现"——31 个实现,各有各的历史包袱,统一行为在工程上几乎不可能
- 纵深防御是唯一现实路径:DNSSEC 挡投毒,0x20 增熵,速率限制增成本——不是消灭攻击,是让攻击不划算
参考
- 论文:
One Char to Rule Them All,IEEE S&P 2026,DOI10.1109/SP63933.2026.00260 - PPT:
https://i.blackhat.com/Asia-26/Presentations/BHAS26-Miao-One-Char-to-Rule-The.pdf - 配套:
RebirthDay Attack,ACM CCS 2025 - dnsmasq 披露讨论:
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2025q3/018289.html - CVE:CVE-2025-40776(BIND9)、CVE-2025-5994(Unbound)
- 第一作者主页:
https://www.miaofs18.top/
2026 年 11 月