一、概述

近期,Linux 内核爆出高危本地提权漏洞 CVE-2026-31431(Copy Fail),影响范围十分广泛。该漏洞源于 AF_ALG 加密子系统在处理 splice 零拷贝数据时,对 scatterlist 的不当合并优化,导致攻击者可将任意可读文件的页缓存页“嫁接”到目标缓冲区,实现对 setuid 程序的内存级代码篡改。

  • 漏洞原语: AF_ALG + splice → 4 字节可控写入任意可读文件的页缓存。
  • 利用方式: 反复调用原语,将 /usr/bin/su 的页缓存逐步替换为 shellcode。
  • 触发方式: execve("/usr/bin/su") → 内核直接加载已被篡改的页缓存版本。
  • 利用结果: shellcode 以 setuid-root 权限运行,su 的密码验证逻辑从未被执行。

天穹沙箱已针对该漏洞增加专项监控规则,能够实时捕获 AF_ALG + splice + execve 组合调用链,并记录攻击特征,辅助安全人员快速定位利用行为。

二、漏洞信息

  • 漏洞编号: CVE-2026-31431
  • 影响组件: Linux 内核 crypto/af_alg.c 及 scatterlist 处理逻辑。
  • 影响版本: Linux kernel 4.9 – 6.8(含);引入点为 2017 年 scatterlist 合并优化(约 v4.9);国产系统:kylin V10/V11 ARM64、UOS 20 x86_64、openEuler 22.03 SP2 ARM64 等均受影响;已于 6.9-rc1 修复。
  • 漏洞类型: 越界写入(Out-of-Bounds Write,CWE-787);页缓存污染(Page Cache Poisoning)。
  • 漏洞评分: CVSS 3.1:7.8(本地提权,无需特权,无需交互)。
  • 补丁状态: 上游已发布补丁,建议升级至 6.9+ 或应用厂商安全更新。

三、攻击全景:页缓存是如何被“偷梁换柱”的?

1. 攻击概述

为了实现无文件落地的内存提权,攻击者巧妙利用了 Linux 页缓存与 scatterlist 的特性:

  • 打开 suid 文件并获取只读文件描述符(例如 /usr/bin/su);
  • 通过 pipe + splice 零拷贝,将 su 的页缓存页引用”注入” AF_ALG 请求的 scatterlist;
  • 触发 authencesn 等算法的越界写操作,4 字节 shellcode 片段被精准写入 su 页缓存;
  • 调用 execve("/usr/bin/su"),内核加载已被污染的页缓存,shellcode 以 root 权限执行。

2. 攻击流程

attack_workflow

图1 漏洞利用攻击流程

3. 核心数据结构:scatterlist

Linux 内核使用 scatterlist 描述物理上不连续的内存块:

1
2
3
4
5
6
struct scatterlist {
unsigned long page_link; // 指向物理页
unsigned int offset; // 页内偏移
unsigned int length; // 这段数据的长度
dma_addr_t dma_address; // DMA 映射后的总线地址
};

多个 scatterlist 条目可通过 sg_chain() 串联,形成逻辑上连续的数据流。

4. AF_ALG 与“就地优化”的致命缺陷

2017 年的一次性能优化将 src 与 dst scatterlist 合并为同一链,省去一次内存拷贝:

1
2
优化前:src → [用户数据页]      dst → [输出缓冲页]
优化后:src = dst → [用户数据页 + 输出缓冲页,链在一起]

当用户通过 splice()/usr/bin/su 的缓存页喂入 AF_ALG socket 时,内核的 af_alg_sendmsg 路径调用 iov_iter_get_pages() 直接获取 struct page * 指针,并用 sg_set_page() 插入 scatterlist,再通过 sg_chain() 追加到 dst 末尾。

authencesn 算法在处理 ESN 时,需要写入 dst[assoclen + cryptlen] 位置。由于 scatterlist 已链式连接,写指针自然越过攻击者控制的缓冲区,滑入 su 的缓存页,实现 4 字节任意写入。

5. splice() 零拷贝的“双刃剑”

1
2
3
4
5
6
普通 read() + write():
磁盘 → 页缓存 → 用户缓冲区 → 内核缓冲区 (两次拷贝)

splice():
磁盘 → 页缓存 ----------------------→ 目标fd (零拷贝)
直接传递页面引用

攻击者利用 splice 的逻辑示意:

1
2
3
r_fd, w_fd = os.pipe()
os.splice(su_fd, w_fd, 4096) # su 的页缓存页进入 pipe
os.splice(r_fd, alg_fd, 4096) # 页面引用送入 AF_ALG socket

6. setuid 授权与页缓存执行的矛盾

当内核处理 execve("/usr/bin/su") 时,分两步走:

1
2
步骤 1:检查 suid 权限 ← 读取磁盘 inode 的文件属性(st_mode)  ✓ 合法
步骤 2:加载并执行代码 ← 读取页缓存中的 ELF 内容 ✗ 已被污染

磁盘上的 su 文件属性完好无损,suid 位依然存在,内核合法地将进程 euid 提升为 0。但步骤 B 加载的却是已被 Copy Fail 替换过的页缓存版本。内核从未意识到这两步之间存在矛盾,因为它没有机制去校验“授权的 suid 程序”和“从页缓存加载的代码”是否一致。

7. shellcode 替换内容

攻击者通过反复 4 字节写入 shellcode 到目标位置,植入的 shellcode 大致等价于:

1
2
3
setuid(0);
setgid(0);
execve("/bin/sh", NULL, NULL);

execve("/usr/bin/su") 被调用后,CPU 入口点直接指向这段代码,在 euid=0 上下文中执行 root shell,整个 PAM 认证栈与 /etc/shadow 读取逻辑均未运行。

四、天穹沙箱检测

天穹沙箱具备基于行为序列的多阶段行为关联分析能力,能够有效检出 CVE-2026-31431 的漏洞触发(PoC)及利用(Exp)。

Ubuntu 18.04 x86_64

天穹沙箱 Ubuntu 18.04 x86_64 环境捕获到完整的 AF_ALG + splice 攻击链如图 2 所示。样本首先打开 su 文件获取其文件描述符,随后创建 AF_ALG 套接字并绑定至 aead 加密模式,同时设置加密认证算法为 authencesn(hmac(sha256),cbc(aes))。接着,样本通过 pipe 与 splice 的组合操作,将 su 文件的页缓存传递给 AF_ALG 套接字,并利用 authencesn 模板的逻辑漏洞将控制数据写入页缓存,最终实现本地提权。
样本执行过程调用和创建子进程的逻辑关系如图 3 所示。

Ubuntu18 检测

图2 Ubuntu 18.04 x86_64 漏洞利用检测

Ubuntu18 检测

图3 Ubuntu 18.04 x86_64 漏洞利用进程树

UOS 20 x86_64

在 UOS 20 x86_64 环境中,天穹沙箱同样通过多阶段行为关联分析捕获到了 setuid 页缓存篡改尝试,规则命中率 100%。

投递样本时,系统类型选择信创,分析系统选择 UOS 20 Desktop x86-64,如图 4 所示。分析配置支持自定义配置命令行参数,在命令行参数输入框中填写执行参数即可。

UOS20 检测

图4 UOS20 环境选择

UOS20 检测

图5 UOS 20 x86_64 漏洞利用检测

五、IOC

恶意文件(MD5)

1
2
3
de1d2a9e44ba05f083a40a3fa9530411
cde0721a815d8d2a8e37e291a972e538
7d5f66c7332a4f929e99380f3f496b5d

报告链接
报告链接(Ubuntu18): 天穹沙箱分析报告
报告链接(UOS20): 天穹沙箱分析报告

六、修复建议

优先级 措施
升级内核至 6.9+ 或应用各发行版厂商发布的安全补丁
对无 DMA/crypto 业务需求的系统,通过 CONFIG_CRYPTO_USER_API_AEAD=n 禁用 AF_ALG AEAD 接口
部署 seccomp 策略,限制非特权进程对 socket(AF_ALG, ...) 的调用
启用 fs.protected_regular=2,增强 suid 程序执行时的页缓存一致性校验(需内核支持)
监控 AF_ALG + splice 组合调用链,对异常进程告警

七、参考链接

八、技术支持与反馈

星图实验室深耕沙箱分析技术多年,致力于让沙箱更好用、更智能。做地表最强的动态分析沙箱,为每个样本分析人员提供便捷易用的分析工具,始终是我们追求的目标。各位同学在使用过程中有任何问题,欢迎联系我们。