CVE-2026-98432 拆解:TCP 握手竞态 UAF、两行 kfree_rcu 修复与 53 分钟的 root exploit

AILinux安全

10 月 27 日,Anthropic 的 Frontier Red Team 发布研究披露:一个未发布的内部 Claude 研究模型,在仅有的初始提示之后,独立写出了一个针对 Linux 内核漏洞 CVE-2026-98432 的远程利用。利用链从发包到拿到 root shell 共耗时约 53 分钟,其中 48 分钟用于泄露一个内核指针打穿 KASLR,最后 5 分钟完成命令执行。前提只有一个:目标服务器上存在一个 Multipath TCP(MPTCP)监听套接字。整个过程不需要凭据,也不需要目标主机上的任何用户做任何事。

这份披露把一个已经修了三个星期的内核 bug 重新拉回聚光灯下。修复本身早已进入所有维护中的 stable 分支,但截至 10 月 30 日,Ubuntu 和 RHEL 这两个装机量最大的发行版还没有发布任何可安装的修复包。漏洞代码从 2016 年的 Linux 4.4 就开始随每个发行版出货,触发点在 TCP 三次握手里,位于任何应用代码收到连接之前。

请求套接字的一次所有权移交

漏洞本体在 tcp_v4_syn_recv_sock(),也就是握手最后一环、把半开连接转正为完整 socket 的函数。修复提交 e3f33b0 对这次移交的描述是:函数把请求套接字里保存的 IP options(ireq->ireq_opt)移交给新的子 socket,方式是转移指针所有权,而不是拷贝一份。

问题出在并发上。自 2016 年的提交 079096f103fa 起,请求套接字不再持有监听锁处理,同一时刻可以有另一个 CPU 在为同一个请求套接字处理重传的 SYN,并在 tcp_check_req() 里构造 SYN-ACK 回包。构造回包的路径在 rcu_read_lock() 保护下读取 ireq_opt,随后 ip_options_build() 会把 opt->optlen 读两次。而子 socket 一旦建立又立刻关闭,inet_sock_destruct() 用普通的 kfree() 释放这份 options——没有任何机制阻止「还在读的 CPU」读到「刚被释放的内存」。这就是 use-after-free。

提交说明还排除了一种疑似的竞态来源:SYN-ACK 定时器本身是安全的,它持有请求套接字的引用,且 inet_csk_reqsk_queue_drop() 会在子 socket 释放前调用 timer_delete_sync()。真正的敞口只有上面那条并发读路径。

CVE-2026-98432 修复提交:两处 kfree 改为 kfree_rcu

修复小到出乎意料:inet_sock_destruct() 和 tcp_v4_reqsk_destructor() 里的两处 kfree() 改成 kfree_rcu(),等所有读者退出 RCU 宽限期后再真正释放。两个文件各改一行。提交说明补了一句:其他替换 options 的代码路径(do_ip_setsockopt()、cipso_v4_sock_setattr())早就在用 kfree_rcu() 了,这两处属于漏网之鱼。

两条触发路径,MPTCP 为什么出现在 PoC 前提里

第一条路径就是上面的握手竞态,远程可达:攻击者发来的 SYN 必须携带 IP options(IP 头 IHL 字段不等于 5),否则请求套接字里根本没有 ireq_opt 这个对象可供释放。这条路径对普通 TCP 和 MPTCP 监听都成立。

第二条路径藏在请求套接字迁移里。开启 net.ipv4.tcp_migrate_req=1 或使用 BPF_SK_REUSEPORT_SELECT_OR_MIGRATE 程序时,reqsk_timer_handler() 会用 inet_reqsk_clone() 克隆请求套接字,新旧两个对象共享同一份 ireq_opt,迁移过程把旧对象里的指针清掉。此时另一个还持有旧请求套接字引用的 CPU 可能正在用这份 options 发 SYN-ACK 或建子 socket,克隆被释放时同样构成 UAF。这个参数默认值为 0,绝大多数服务器不会踩到。

MPTCP 在 Anthropic 的 PoC 里扮演的角色,披露原文没有展开解释。可以确认的事实是:CVE 记录和修复提交都没有把 MPTCP 列为漏洞条件,公开的 root RCE 演示只在 MPTCP 监听配置下完成过;普通 TCP 路径的利用难度更高,目前没有公开的复现。CloudLinux 的内核团队公开表示无法复现 Anthropic 的声明,利用代码未公开,也没有任何在野利用的报告。

从 2016 年到 10 月 27 日

引入点是 2016 年 1 月随 Linux 4.4 发布的 079096f103fa,去掉监听锁、把请求套接字装进 ehash 表的那次重构;迁移路径的引入点则是后来的 c905dee62232。也就是说,这十年间出货的几乎所有 Linux 服务器内核都带着这条竞态路径。

2026 年 10 月 1 日,Eric Dumazet 提交修复,提交署名 Reported-by: Xinyang Ge ([email protected]),Kuniyuki Iwashima 审查。10 月 5 日合入网络树。修复随后按稳定分支节奏铺开:10 月 11 日进入 7.2.10 和 6.18.56;10 月 15 日进入 6.12.113、6.6.159、6.1.190、5.15.223、5.10.272,同日 CVE 记录在 cve.org 公布;10 月 18 日,mainline 7.3 带着修复发布。IPv6 的第一条路径不受影响,因为 tcp_v6_syn_recv_sock() 对 options 做的是拷贝;IPv6 迁移路径上与 CALIPSO 相关的同类问题,官方说明将在另一个补丁里处理。

10 月 24 日,内核 CVE 团队给记录加上 CVSS 3.1 9.8 分。10 月 27 日,Anthropic 发布前文提到的研究披露。这条时间线里还有一个事实:从上游修复到 Anthropic 公开披露隔了 26 天,Anthropic 的协同披露政策给厂商 90 天补丁期,外加 45 天的细节讨论缓冲期,这次披露远在缓冲期之内。

修复进度:上游收口之后,包还没发到最大的两家

上游分支全部有修复,不等于服务器已经安全。发行版内核自带回移植,版本号与上游对不上,实际状态要看各家 tracker:

发行版 / 内核状态(10 月 29–31 日)凭据
Debian 12 bookworm已修:linux 6.1.190-1(DLA-4841-1)、linux-6.12 6.12.113-1~deb12u1(DLA-4850-1)官方公告
Debian 13 trixie已修:6.12.113-1(DSA-6568-1,10 月 16 日)官方公告
Ubuntu 全系tracker 全线 Vulnerable,22.04–26.10 标注 work in progress,修复包在 proposed 仓库可手动拉取,无 USNUbuntu tracker
RHEL 8 / 9 / 10受影响,无修复包;Red Hat 称现有缓解不满足其产品安全标准;RHEL 6/7 不受影响Red Hat CVE 页
Oracle LinuxUEK 已修(ELSA-2026-500397/98/99,10 月 16 日)官方勘误
Amazon Linux 2023kernel6.18 已修(10 月 24 日)、kernel6.12 已修(10 月 29 日);默认 kernel 包与 Amazon Linux 2 仍待修ALAS 公告
SUSESLES 16.0 与 15 SP4/SP5/SP6 LTSS 已修;SP7 处理中;openSUSE Leap 15.6/16.0 受影响SUSE CVE 页
Proxmox7.0.14-25 已进全部仓库(企业仓库 10 月 31 日凌晨放行)官方论坛

Ubuntu 安全 tracker 上 CVE-2026-98432 的修复状态

Ubuntu 和 Red Hat 的滞后在 HN 上引来大量不解。合理的解释是回移植需要走完整的回归测试,Ubuntu 的修复包已经进了 proposed 仓库等待推送;但 Red Hat 对影响评级的态度是另一回事,它把这条漏洞的后果主要描述为崩溃或潜在的内存损坏,与 Anthropic 拿出的 root shell 演示之间存在明显落差。

9.8 对 8.1,分歧出在攻击复杂度

内核 CNA 给出的向量是 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H,攻击复杂度 Low,三项影响全部 High。Red Hat 打 8.1,差别在它把攻击复杂度标成 High。Oracle 和 Amazon 跟随 Red Hat 的 8.1 口径,Ubuntu 标 High 不给数值,SUSE 标 important。

分歧的核心是一个事实问题:赢下这场内核竞态到底算不算「低复杂度」。Anthropic 的演示证明至少在一种配置下可以稳定打穿,但那套利用依赖特定的监听配置、允许无限重试的失败模式,以及 48 分钟级的自动化耐心。NVD 目前对这条 CVE 的状态是 Received,没有自己的分析;未进入 KEV 目录;在野利用为零。三个信号叠在一起,9.8 与 8.1 之间的四个点,实际是在问「实验室演示」与「武器化门槛」之间的距离该怎么折算。

Go 1.24 把 MPTCP 变成了默认

MPTCP 允许一条 TCP 连接同时使用多条网络路径,需要连接两端的应用显式启用。多年来大多数团队可以安全地假设自己没有在用它,Go 改变了这个假设:从 Go 1.24 起,Linux 上 net.Listen 打开的监听套接字默认请求 MPTCP(内核支持时),出站连接保持普通 TCP。10 月 29 日,Go 安全团队的 Neal Patel 在 golang-announce 发信确认了这个默认行为与 CVE-2026-98432 的关系,次日由 oss-security 转发。

一封 Go 程序的 API 网关、反向代理或内部服务,只要用 Go 1.24 或更新版本构建,就可能持有一个它的主人从未主动开启的 MPTCP 监听。KrakenD 团队实测了自己的产品:用 Go 1.26.10 构建的 KrakenD EE 3.0.2,默认配置下 8080 端口就是 MPTCP 套接字——尽管客户端几乎全部在用普通 TCP 连接进来,但利用只需要监听套接字是 MPTCP。

Go 团队给出的临时手段有三个层级:环境变量 GODEBUG=multipathtcp=0(运行时)、主模块 go.mod 写 godebug multipathtcp=0(构建时)、net.ListenConfig.SetMultipathTCP(false)(逐 socket 覆盖)。同时他们自己把这称为脆弱的缓解:漏掉一个 MPTCP 监听就前功尽弃,而且该缓解假设所有可行利用都依赖 MPTCP。官方建议仍然只有一个——升级到已修复的内核。至于把默认行为改回去,Go 团队认为为时过早(golang/go#82717)。另有一个环境变量常被忽略:EL 8/9/10 系发行版默认 net.mptcp.enabled=0,原生 EL 主机上 Go 程序开不出 MPTCP 监听,除非有人手动打开过这个开关。

检查与缓解

按优先级排列:

  1. 确认内核版本。uname -r 看运行内核,对照上表发行版状态,不是对照上游版本号。装了新内核没重启等于没修;容器里的内核就是宿主机内核,换镜像没有用,要查的是宿主机和 Kubernetes 节点。
  2. 盘点 MPTCP 监听。ss -Mlnp 列出所有 MPTCP 监听套接字及属主进程,sysctl net.mptcp.enabled 看系统级开关。Go 1.24+ 构建的网络服务是重点排查对象。
  3. 临时缓解按需叠加。运行时关 MPTCP 要把 net.mptcp.enabled=0 写进持久化配置,重启后 sysctl -w 的设置会丢;边界防火墙丢弃携带 IP options 的 SYN(IHL 不等于 5)可以掐断已知触发链,代价是破坏少数合法使用 IP options 的流量;FreeBSD 的负载均衡器默认丢弃这类包。躲在 AWS ALB、CloudFront、API Gateway 等边缘服务后面、不直接从不可信来源收 TCP 连接的场景,AWS 的公告判定暴露面有限。
  4. 等待并安装发行版修复包。这是唯一完整方案。Ubuntu 用户可以手动从 proposed 仓库拉包,其余的等正式推送。

一条由模型完成的攻击链

回到 10 月 27 日那份披露本身。这条 Linux 利用链是五个演示之一,同一篇帖子还覆盖了 Chrome 一键代码执行链、Safari 同源策略绕过链、Pixel 9 锁屏绕过,以及 Windows HTTP/3 栈的远程崩溃(CVE-2026-33096,CVSS 7.5)。需要分清的是分工:发现并报告这个内核漏洞的是 Anthropic 研究员 Xinyang Ge,修复提交里的 Reported-by 署名是这条事实的原始出处;Claude 的贡献发生在漏洞已知之后,从初始提示出发独立完成了利用开发。披露给出的时间线——48 分钟泄露内核指针、5 分钟拿到 shell、输掉竞态只是握手失败可以无限重试——描述的是实验环境里的自动化过程。

对内核社区来说,这个漏洞的故事在 10 月 1 日就已经结束:两行 kfree_rcu(),七年半前的设计决策在并发模型变化后变成敞口,修复进入所有维护分支。剩下的部分属于发行版的发布流水线,以及每个还没重启的服务器。

来源:修复提交 e3f33b0 · Anthropic 研究披露 · golang-announce 经 oss-security 转发 · CVE-2026-98432 记录 · Ubuntu tracker