732 字节拿下 Root:CVE-2026-31431 Linux 内核提权漏洞分析

CVE-2026-31431 是一个 Linux 内核加密子系统漏洞,无需竞态条件,一个 732 字节的 Python 脚本即可在 Ubuntu、RHEL、Amazon Linux 等主流发行版上以普通用户身份拿到 Root。本文解析漏洞根因、利用路径与修复方案。

阅读时长: 4 分钟
共 1953字
作者: eimoon.com

Xint Code 披露了 CVE-2026-31431,一个存在于 Linux 内核认证加密子系统中的严重漏洞。它让无特权用户只需运行一个小小的 Python 脚本,就能在所有主流 Linux 发行版上拿到 Root。

这个漏洞之所以与众不同,在于它不需要任何竞态条件或时序技巧,是一个"直线型逻辑缺陷"——同一份未经修改的利用脚本,可以不加任何适配地直接跑在 Ubuntu、Amazon Linux、RHEL 和 SUSE 上。

漏洞背景

与 Dirty Cow、Dirty Pipe 的区别

过去十年里,Dirty Cow(2016)和 Dirty Pipe(2022)是 Linux 提权漏洞里最广为人知的两个名字。它们都依赖竞态条件:攻击者需要精确抢占内核执行窗口,成功率受环境影响,复现也更复杂。

CVE-2026-31431 走的是另一条路。它是一个确定性逻辑漏洞,不依赖时序,不需要反复重试,每次执行路径都是一样的。这直接决定了它的利用脚本可以做到极度精简,同时兼容多个发行版。

受影响版本

在以下环境验证可成功利用:

发行版 内核版本
Ubuntu 24.04 LTS 6.17.0
Amazon Linux 2023 6.18.8
RHEL 10.1 6.12.0
SUSE 16 6.12.0

根因:AF_ALG + splice + authencesn

漏洞的核心在于三个内核机制的组合:AF_ALG socketsplice()authencesn AEAD 算法

AF_ALG 是什么

AF_ALG 是 Linux 内核提供的一种特殊 socket 类型,作用是把内核的加密函数暴露给用户空间。应用程序可以通过它调用硬件加速加密,而不用把数据拷贝到用户态再处理。

splice() 的语义

splice() 的设计目标是在两个文件描述符之间零拷贝传输数据。它传递的是页缓存页面的引用,而不是数据副本。正是这个"传引用"的设计,把问题引了进来。

authencesn 的 scratch 写入

authencesn 是一种 AEAD(认证加密)算法,在解密过程中需要一块临时工作区。它会把 4 个字节写入目标缓冲区偏移 assoclen + cryptlen 的位置,用作中间计算的暂存空间。

2017 年,内核引入了一项优化,让 AEAD 操作可以原地进行(in-place)——即源缓冲区与目标缓冲区共用同一块内存,省去额外拷贝。

三者叠加之后,漏洞路径就打通了:

  1. 用户通过 splice() 把文件(比如 /usr/bin/su)的页缓存页面"喂"给 AF_ALG socket
  2. 由于原地优化,这些页缓存页面直接落入 authencesn 的可写目标 scatterlist
  3. 解密触发时,authencesn 把 4 字节的 scratch 数据写进了真实的页缓存
  4. HMAC 校验失败,操作报错,但那 4 字节已经写进去了
  5. 关键一点:内核的 writeback 机制从未把这个被改动的页面标记为 dirty,文件完整性检查因此失效

利用路径

攻击流程的核心步骤如下:

1. 打开 AF_ALG socket,绑定到 authencesn 算法
2. 构造 sendmsg() 调用,控制写入的 4 字节内容
   (利用 ESN 扩展序列号字段)
3. 用 splice() 把 /usr/bin/su 的页缓存页面作为"密文"传入
4. 触发解密,authencesn 将受控字节写入页缓存
5. 执行被改写后的 su,借助其 setuid 权限获得 Root

整个利用脚本只使用 Python 标准库,体积 732 字节

为什么"脏页"检测失效

这是这个漏洞最精妙也最危险的地方。

通常,内核会通过 dirty page 标记来追踪哪些页面被改动过,进而决定是否回写到磁盘、是否触发 fsync 相关的完整性检查。Dirty Pipe 也利用过类似机制。

但 CVE-2026-31431 走的路径恰好绕过了这个标记机制:authencesn 的 scratch 写入发生在 AEAD 内部处理流程中,属于"中间计算副作用",内核的 writeback 子系统从未介入,页面始终显示为"干净"。这意味着:

  • 文件系统层面看不到改动
  • IMA(Integrity Measurement Architecture)等完整性机制可能无法检出
  • 被修改的 setuid 二进制正常执行,没有任何异常信号

修复方案

补丁的思路直接针对根因:将 AF_ALG AEAD 操作从原地模式(in-place)回退为非原地模式(out-of-place)

具体做法是把源 scatterlist 与目标 scatterlist 分离,确保页缓存页面永远不会进入 authencesn 的可写目标 scatterlist,scratch 写入也就不再能触及实际文件内容。

这个修复代价很小——放弃 2017 年那个原地优化——但彻底切断了攻击路径。

临时缓解措施

在内核补丁可用之前,可以采取以下措施降低风险:

  • 通过 seccomp 策略阻止 AF_ALG socket 的创建
  • 卸载或禁用 algif_aead 内核模块:modprobe -r algif_aead
  • 限制对 splice() 相关系统调用的访问(影响范围较大,需评估)

发现过程

这个漏洞由 Theori 研究员 Taeyang Lee 发现。他判断 AF_ALG + splice() 是一个值得深挖的可疑攻击面,随后借助 Xint Code 的自动化分析能力,重点关注页缓存来源(page cache provenance),在大约一小时内定位到了这个漏洞。


这个漏洞很好地说明了一件事:内核中的性能优化(原地 AEAD)和零拷贝机制(splice 传引用)在组合之后,可能产生任何一方单独都不会引发的安全问题。漏洞不一定藏在复杂的代码里,有时候它就在两个"各自正确"的设计之间的缝隙里。

目前 Xint Code 还预告了 Part 2,将覆盖 Kubernetes 容器逃逸场景,届时攻击面会进一步扩大。

关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号

原文:Copy Fail: 732 Bytes to Root on Every Major Linux Distribution,作者 Xint Code,本文为编译整理,许可协议 CC BY-SA 4.0。

使用 Hugo 构建
主题 StackJimmy 设计