对 Theori/Xint 针对 CVE-2026-31431 的概念验证代码进行教育性重写。该漏洞是 Linux 内核 algif_aead 加密套接字接口中的一个本地权限提升漏洞。影响从 4.14(2017 年 7 月)到 6.18.21 的所有主线内核,以及 6.19 稳定分支至 6.19.11。
仅用于教育和授权的安全研究。 请勿在非您所有或未经明确书面许可的系统上运行。在易受攻击的主机上运行此程序将使任何非特权本地用户立即获得 root 访问权限。作者对滥用行为不承担任何责任。
自内核 3.2 起,Linux 内核通过 AF_ALG 套接字家族(<linux/if_alg.h>)向用户空间暴露了内核内加密 API。用户空间打开一个 SOCK_SEQPACKET 套接字,将其绑定到算法模板(例如 "aead" / "authencesn(hmac(sha256),cbc(aes))"),并发送数据进行加密或解密。
2017 年,一个性能优化被合并,允许 AEAD 算法在内核检测到源和目标共享相同底层页面时就地加密或解密数据。这避免了每次操作中冗余的内存复制。
authencesn 模板(为认证加密添加扩展序列号支持)在解密过程中包含一次临时写入:它在认证检查运行之前将 ESN 字节写入操作数据缓冲区内的特定偏移量。当操作的源页面通过 splice() 从常规文件的页缓存获取,并且就地优化处于活动状态时,此临时写入会直接写回那些缓存页面。
由于内核的页缓存是共享映射——任何打开同一文件的进程都会看到相同的物理页面——非特权用户可以:
O_RDONLY 打开任何可读文件(例如 /usr/bin/su)。splice() 传入 AF_ALG 操作套接字。authencesn 解密;ESN 临时写入会在受控偏移量处用攻击者控制的字节破坏页面。比较磁盘文件校验和的离主机完整性扫描器(AIDE、Tripwire、IMA/EVM)对此攻击完全不可见。写入会在页缓存驱逐或重启后消失,在磁盘上不留任何取证痕迹。
通过针对 /usr/bin/su(一个 setuid root 二进制文件)并覆盖保护 PAM 认证检查的分支,攻击者可以获得无密码的 root shell。
引入该漏洞的优化提交于 4.14 开发周期(2017 年 7 月)落地。任何在上述范围内编译时启用了 CONFIG_CRYPTO_USER_API_AEAD=y 和 CONFIG_CRYPTO_AUTHENC=y(两者均为常见默认配置)的内核均易受攻击。
请查阅您发行版的安全跟踪器以获取确切的安全公告状态。
os.splice 在 Python 3.10 中添加)/usr/bin/su,由于是 setuid 文件,全局可读)# 显示将要写入的内容而不触及内核(安全):
python3 copy_fail_exploit.py --dry-run
# 修补 /usr/bin/su 页缓存(需要易受攻击的内核):
# 警告:需要易受攻击的内核——仅可在您拥有的系统上使用
python3 copy_fail_exploit.py
# 修补并立即提升到 root:
python3 copy_fail_exploit.py --spawn-shell
# 使用自定义目标二进制文件和载荷:
python3 copy_fail_exploit.py --target /usr/bin/sudo --payload-file ./custom_patch.bin
# 详细输出(打印每次 4 字节写入):
python3 copy_fail_exploit.py --verbose --dry-run
默认情况下 --spawn-shell 为关闭状态。修补后,脚本会打印:
[+] Patch applied to page cache of '/usr/bin/su' (disk unchanged).
Run `su` to escalate, or re-run with --spawn-shell.
To restore: echo 3 | sudo tee /proc/sys/vm/drop_caches
您必须通过 --spawn-shell 选择启用 shell 生成。这是有意为之:它迫使您在执行结果之前理解漏洞利用做了什么。
设置原语。
漏洞利用打开一个 AF_ALG 套接字,并将其绑定到带有虚拟全零密钥的 authencesn(hmac(sha256),cbc(aes)) 模板。然后通过 ALG_SET_AEAD_AUTHSIZE 将认证标签大小配置为 4 字节。在控制套接字上调用 accept() 会生成一个操作套接字,可以提交单独的解密请求。
触发页缓存写入。
对于修补载荷的每个 4 字节块,漏洞利用在操作套接字上调用带有 MSG_MORE 标志的 sendmsg(),传递 8 字节的关联数据(AAD):4 字节填充后跟 4 字节载荷。MSG_MORE 告诉内核保持操作直到更多数据到达。然后它创建一个管道并发出两次 splice() 调用——file_fd → pipe → op_sock——将文件自身的页缓存页面作为解密操作的输入。当最终调用 recv() 时,内核运行 authencesn 解密。就地优化触发(源和目标为相同页面),ESN 临时写入将我们的载荷字节复制到目标偏移量的缓存页面中。recv() 返回 EBADMSG,因为认证标签无法验证——这是预期且无害的。写入已经发生。
修补二进制文件。
嵌入的载荷(直接取自 Theori PoC)覆盖了标准 util-linux 构建中 /usr/bin/su 的分支指令,将强制 PAM 认证的条件跳转变为无条件直通。修补后,无需密码运行 su 即可成功并获得 root shell。磁盘上的二进制文件未被触及;丢弃页缓存条目(echo 3 > /proc/sys/vm/drop_caches)可立即还原更改。
如需更深入的技术分析,请参阅下面的参考资料,特别是 Xint 博客文章和 Theori PoC 仓库。
- rule: AF_ALG socket opened by unprivileged process
desc: >
CVE-2026-31431 — an unprivileged process opened an AF_ALG (family 38)
socket, which is the first step of the Copy Fail exploit.
condition: >
evt.type = socket and
evt.arg.domain = 38 and
not user.uid = 0
output: >
AF_ALG socket opened (user=%user.name uid=%user.uid
pid=%proc.pid comm=%proc.name)
priority: WARNING
tags: [host, network, privilege_escalation, CVE-2026-31431]
rule CopyFail_CVE_2026_31431 {
meta:
description = "Detects Copy Fail exploit script in memory or on disk"
cve = "CVE-2026-31431"
strings:
$template = "authencesn(hmac(sha256),cbc(aes))" ascii
$splice = "os.splice" ascii
$aflag = "AF_ALG" ascii
condition:
all of them
}
添加到 /etc/audit/rules.d/cve-2026-31431.rules:
-a always,exit -F arch=b64 -S socket -F a0=38 -k cve_2026_31431_afalg
然后使用以下命令查看日志:
ausearch -k cve_2026_31431_afalg --interpret
1. 应用内核补丁(推荐) 升级到内核 6.18.22、6.19.12、7.0-rc7 或更高版本,或应用您发行版的安全更新。
2. 在构建时禁用 CONFIG_CRYPTO_USER_API_AEAD 如果您自行构建内核,请设置:
# CONFIG_CRYPTO_USER_API_AEAD is not set
这将移除整个 AF_ALG AEAD 接口并消除攻击面。大多数嵌入式/加固部署不需要它。
3. seccomp — 拒绝 AF_ALG 套接字家族
为敏感进程(或通过 LSM 策略系统级)添加拒绝 socket(AF_ALG, ...) 的 seccomp 过滤器:
// Deny socket() when domain == AF_ALG (38)
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 38, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EACCES),
4. 通过内核加固降低页缓存权限
vm.unprivileged_userfaultfd=0 及类似的调优参数可减少用户可访问的内核内存接口的攻击面,尽管它们不能直接阻止此 CVE。
漏洞利用仅修改内存中的页缓存;磁盘上的二进制文件从未被触及。要恢复内存中的原始文件内容,请丢弃内核的页缓存:
echo 3 | sudo tee /proc/sys/vm/drop_caches
这将从缓存中驱逐所有干净页面。下次读取 /usr/bin/su(或任何被修补的二进制文件)时将从磁盘重新加载原始字节。
重启也会完全清除页缓存。
MIT — 参见 LICENSE。
选择 MIT 而非自定义的"仅限教育用途"许可证,是因为不存在被认可的 OSI/SPDX 标识符对应的此类许可证。MIT 是宽松的、法律上被充分理解的,并且与负责任披露仓库兼容。教育意图在模块文档字符串、本 README 的免责声明部分以及 --help 输出中表达——而非在法律上可疑的自定义许可证条款中。
| 分支 | 首个受影响版本 | 最后受影响版本 | 修复版本 |
|---|
| 主线 | 4.14 | 6.18.21 | 6.18.22 |
| 6.19 稳定版 | 6.19.0 | 6.19.11 | 6.19.12 |
| 7.0-rc | 7.0-rc1 | 7.0-rc6 | 7.0-rc7 |
| 发行版 | 自带内核(约) | 已修补? |
|---|
| Debian 12 (Bookworm) | 6.1.x | 是(向后移植) |
| Debian 13 (Trixie) | 6.12.x / 6.14.x | 是(向后移植) |
| Ubuntu 24.04 LTS | 6.8.x | 是(USN-7xxx) |
| Ubuntu 24.10 | 6.11.x | 是 |
| RHEL 9.x | 5.14.x(重新基于) | 是(RHSA) |
| Alpine 3.20 | 6.6.x | 是(向后移植) |
| Arch Linux | 滚动更新(现在 ≥ 6.18.22) | 是 |
| Kali Linux 2026.1 | 6.18.12 | 易受攻击 |
| Kali Linux 2026.2+ | 6.18.22+ | 已修复 |
| Linux Mint 22 | 6.8.x(基于 Ubuntu) | 是(Ubuntu USN) |