0xCyberstan/CVE-2026-31694-POC
GitHub: 0xCyberstan/CVE-2026-31694-POC
针对 Linux 内核 FUSE readdir 缓存越界写入漏洞(CVE-2026-31694)的 PoC 与本地提权利用,通过 page-cache 损坏实现无密码 root 提权。
Stars: 14 | Forks: 2
# CVE-2026-31694:FUSE readdir 缓存越界写入
`fs/fuse/readdir.c:fuse_add_dirent_to_cache()` 中缺少边界检查。一个 FUSE
服务器返回了一个 `namelen = 4095` 的 dirent,它被序列化为一条
4120 字节的记录。内核将其复制到一个仅有 4096 字节的 page-cache 页面中,
并溢出了 24 个由服务器控制的字节,进入到了下一个物理页面。
这个仓库包含一个用于写入原型的标记 PoC,以及一个本地权限提升(LPE)漏洞利用。
它通过精确的内存布局(grooming),将溢出数据定向到 `/etc/passwd` 的 page-cache 副本上,
从而将 root 账户转换为一个无密码账户。
- 受影响版本:Linux 6.15+(将 `FUSE_NAME_MAX` 提升至 `PATH_MAX - 1` 使得
readdir 路径变得可达)
- 修复方案:`51a8de6c50bf9` "fuse: reject oversized dirents in page cache"(五个稳定版
回移(backport)补丁之一)
- CVE-2026-31694
## 警告:仅限虚拟机使用,切勿在裸机上运行
这种溢出是内核向 FUSE 缓存页面紧接的下一个物理页面写入数据。漏洞利用通过布局尝试将
写入定向到选定的页面,但这具有概率性。如果偏离目标,这 24 字节可能会命中无关页面:
- 其他文件的缓存页面,包括将被写回磁盘的脏页面(dirty pages),这会
破坏真实文件,
- 内核数据,可能导致机器 panic 或造成静默数据损坏。
仅在一次性虚拟机中运行它。这里的脚本始终在 QEMU/KVM 内运行漏洞利用,
从不在宿主机上运行。
## 目录结构
```
exploit.c the PoC and LPE (single file, static build)
Makefile builds ./exploit (static)
vm/config.sh all paths and settings (edit KERNEL_TREE)
vm/make_rootfs.sh build the Ubuntu 24.04 guest image (run as root)
vm/build_vuln_kernel.sh build a vulnerable bzImage from your kernel tree
vm/run_vm.sh boot the guest headless
vm/provision_guest.sh in-guest setup (runs over ssh)
vm/run_in_vm.sh one command: boot, provision, run, verify
```
## 环境要求
宿主机:带有 KVM 的 Linux(存在 `/dev/kvm`,你的用户属于 `kvm` 组),并且需要:
- `qemu-system-x86_64`、`sshpass`、`gcc`、`make`
- 运行 `make_rootfs.sh` 还需要:`debootstrap`(以及 root 权限)
你还需要一个 Linux 内核源码树,以便从中构建存在漏洞的内核。
## 设置说明
1. 编辑 `vm/config.sh`。你必须设置的唯一值是 `KERNEL_TREE`:即
Linux 源码检出路径。请使用修复补丁 `51a8de6c50bf9` 之前的版本
(任何 6.15..7.0 的检出都存在此漏洞)。如果该源码树已经包含了修复补丁,
`build_vuln_kernel.sh` 会在构建期间移除该防护检查,并在构建完成后恢复该文件。
其他所有配置(内存、CPU、SSH 端口、镜像路径)都有默认值,你可以直接
保留默认。任何值也可以通过环境变量设置,
例如 `KERNEL_TREE=/path/to/linux vm/run_in_vm.sh`。
2. 构建客户机镜像(Ubuntu 24.04,debootstrap 需要 root 权限):
sudo vm/make_rootfs.sh
这将创建一个 `test:test` 的 sudo 用户、一个串行控制台、SSH 密码认证
以及 fuse3。
3. 构建存在漏洞的内核:
vm/build_vuln_kernel.sh
## 运行
端到端执行(启动、配置、标记 PoC、LPE、验证 uid 0):
```
vm/run_in_vm.sh
```
手动执行:
```
vm/run_vm.sh & # boot headless; console goes to vm/serial.log
make # build the static exploit
# 将 ./exploit 复制到 guest 中,然后以 test 用户身份执行:
./exploit --poc -n 20 # marker test
./exploit # warmup, then LPE
```
停止虚拟机:
```
pkill -f bzImage-fuse-vuln
```
## exploit 选项
```
--poc marker mode only, no /etc/passwd changes
-n N number of rounds
(no args) 5 warmup rounds, then up to 200 LPE attempts; on success it writes a
passwordless root line to /etc/passwd and drops caches
```
## 预期输出
Marker 模式会打印每轮命中次数和总次数,例如 `20/20 (100.0%)`。
LPE 模式会打印 `Warmup: 5/5`,随后是一行 `LPE n/200 ... HIT!`,并将
`/etc/passwd` 的第一行从 `root:x:0:0:root:/root:/bin/bash` 修改为
`root::0:0:root:/root:/bin/sh`,随后使用空密码执行 `su -s /bin/sh root`
将返回 uid 0。
## 原理解析
readdir 缓存路径会将每个 dirent 复制到一个 page-cache 页面中。大小检查
仅判断该 dirent 是否适合当前页面的剩余空间;它
从未检查过该 dirent 是否能完整放入一个页面中。当 `namelen = 4095` 时,
记录大小为 4120 字节,因此此次复制会越过一个全新页面的末尾 24 字节。
漏洞利用首先排空每 CPU 页面(PCP)空闲链表,以便分配器从 buddy 分裂中分配
物理上相邻的页面,然后将 readdir 缓存
页面与受害页面安排为相邻页面。对于 LPE,受害页面是 `/etc/passwd` 的 page-cache
副本:这 24 字节的溢出重写了 root 的行,使其密码
字段变为空,并且在 PAM 开启 `nullok`(Ubuntu 默认开启)的情况下,`su root` 随后即可
使用空密码成功登录。
完整分析:[https://cyberstan.co.uk/fuse-readdir-oob/](https://cyberstan.co.uk/fuse-readdir-oob/)
## 漏洞披露
由 Qi Tang 和 Zijun Hu 在上游报告;修复补丁由 Samuel Page 编写。
我独立发现并报告了此漏洞。上游致谢和 CVE-2026-31694 归属于他们。该漏洞已在
主线和稳定版分支中修复。
## 许可证
MIT,详见 `LICENSE`。仅供教育和授权测试使用。
标签:Cutter, FUSE, Linux内核, PoC, Web报告查看器, 安全渗透, 客户端加密, 暴力破解, 本地提权