Rat5ak/CVE-2026-41285-OpenBSD-v6daemons-go-brrr
GitHub: Rat5ak/CVE-2026-41285-OpenBSD-v6daemons-go-brrr
针对 OpenBSD slaacd/rad 守护进程的 CVE-2026-41285 PoC,通过发送一个 ND 选项长度为零的 ICMPv6 数据包触发整数下溢无限循环,实现永久性 IPv6 SLAAC 服务拒绝。
Stars: 0 | Forks: 0
# CVE-2026-41285:一个数据包导致 OpenBSD 上的 IPv6 瘫痪
来自本地网络的一个特制 ICMPv6 数据包会永久挂起 `slaacd`
和/或 `rad`。IPv6 SLAAC 地址自动配置会失效,直到有人手动
重启该守护进程。无需认证,无需权限,仅需 18 字节的 ICMPv6 负载。
| | |
|------------|--------------------------------------------------------------------|
| CVE | CVE-2026-41285 |
| 漏洞类别 | 整数下溢导致的无限循环 |
| 根本原因 | ND 选项解析器执行 `nd_opt_len * 8 - 2` 时未检查 len==0 |
| 组件 | `sbin/slaacd/engine.c`, `usr.sbin/rad/engine.c` |
| 影响 | 导致 IPv6 SLAAC (slaacd) 或 RA 服务 (rad) 遭受永久性 DoS |
| 前提条件 | 同一 L2 网络段上的任何设备 |
| 测试环境 | OpenBSD 7.8 GENERIC amd64 |
## 漏洞详情
RFC 4861 §4.6 规定长度为零的 ND 选项是无效的,必须被
静默丢弃。内核自身在 `sys/netinet6/nd6.c` 中的 `nd6_options()`
正确地执行了这一点。但是,在该检查起作用之前,原始的 ICMPv6 数据包
已经被传送到用户空间 socket。
`slaacd` 和 `rad` 都会自行解析 ND 选项。其循环代码如下所示:
```
while (len > 0) {
// ...
optlen = nd_opt->nd_opt_len * 8 - 2; // nd_opt_len is uint8_t
if (optlen > len)
break;
len += 2;
// advance pointer by optlen... which is (uint32_t)-2 promoted from int
}
```
当 `nd_opt_len == 0` 时:表达式 `0 * 8 - 2` 会被提升为 `int` → `-2`。
判断条件 `(-2 > len)` 始终为假(有符号比较,len 为正值)。
随后 `len += 2` 并且指针后退 2 个字节。循环永远不会向前推进。
CPU 占用率会一直保持在 100%。永久死循环。
内核验证了它自己的副本。而用户空间的守护进程获取的则是原始数据。
没有人通知 slaacd。
## 影响
- 一个数据包 → slaacd 引擎卡在无限循环中,CPU 占用率达 100%
- 所有后续的 RA 均被忽略 → 无法配置新的 SLAAC 地址
- 现有地址最终过期(生命周期耗尽,无法续期)
- 所有由 slaacd 管理的接口上的 IPv6 连通性会逐渐完全中断
- 针对 rad 的相同攻击:一个特制的 RS 即可使该链路的 RA 服务瘫痪
- 恢复需要手动执行 `rcctl restart slaacd` 或重启系统
## PoC
```
python3 poc/kill_slaacd.py
```
需要使用 scapy。发送一个带有一个 `nd_opt_len = 0` 的 ND 选项的
路由通告(Router Advertisement)。就是这样。选项类型并不重要(PoC 使用了类型
200 / 未知)。
完整的端到端证明(展示 SLAAC 正常工作 -> 发起攻击 -> SLAAC 瘫痪):
```
python3 poc/prove_dos.py
```
## 证据
```
── Before exploit ──
SLAAC addresses: 2001:db8:1:0:df6f:edeb:6e3a:2640, ...
Engine CPU: 0.0%
── After one packet ──
Engine CPU: 23.1% → 43.3% (climbing)
New RA with 2001:db8:2::/64 sent → no address configured
slaacd is dead. IPv6 autoconf: DEAD.
```
## 先前案例
与 CVE-2022-27881 和 CVE-2022-27882 的攻击面相同(早期的 slaacd
在 engine.c 中的无限循环,同样发生在 ND 选项解析时)。这是同一类
漏洞的一个新实例 —— 之前的修复并没有覆盖所有的解析循环。
## 修复方案
在对 `nd_opt_len` 进行算术运算之前检查 `nd_opt_len == 0`。并跳出循环。
这正是内核在 `nd6_options()` 中已经执行的操作:
```
if (nd_opt->nd_opt_len == 0)
break; // or: goto bad;
```
针对 slaacd 的 `parse_ra()`、`debug_log_ra()` 以及 rad 的 RS
解析器的建议补丁 —— 这三个循环都需要加上相同的一行代码防护。
## 时间线
- 2026-04-12:附带 PoC 和补丁报告至 security@openbsd.org
- 2026-04-20:由 MITRE 分配了 CVE-2026-41285
## 免责声明
这是一个本地网络的 DoS 攻击。如果你与运行着 slaacd 的 OpenBSD
设备处于同一个 L2 网段,一个数据包就能冻结其 IPv6。请不要将其发送至
你不拥有的网络。如果你正在运行 OpenBSD,请检查是否有补丁或自行添加 len==0 的防护。
Daniel Wade - [GitHub](https://github.com/Rat5ak) · [Twitter/X](https://x.com/Nadsec11) · [Bluesky](https://bsky.app/profile/nadsec.online) · [nadsec.online](https://nadsec.online/)
标签:0day挖掘, C/C++, CVE-2026-41285, DoS, ICMPv6, IPv6, L2网络攻击, NDP, OpenBSD, PowerShell, SLAAC, 事务性I/O, 内核安全, 内核驱动, 安全漏洞, 拒绝服务, 整数下溢, 无限循环, 漏洞分析, 网络协议, 路径探测, 路由发现协议, 逆向工具