圣堂之魂
服务器小记

运维灾难:Linux - 0 Day 漏洞让我彻夜难眠

双 0 Day 凌空来袭,全网运维集体头皮发麻


声明:本文所涉及的漏洞原理、复现步骤、利用代码,仅可用于内部授权安全测试、合规漏洞研究与加固演练。严禁私自用于未授权服务器入侵、非法越权操作等违规违法行为,违者需自行承担全部法律责任与相关后果!


一、平静被撕开一道口子

4 月 30 日下午 17 点,腾讯云服务器的售后群突然发送紧急通知:

Copy Fail 潜伏的 Linux 本地提权漏洞,CVE-2026-31431,POC 已公开。”

我下意识看了一眼自己的服务器内核版本:6.12.57+deb13-amd64,刚好在受影响范围内。

这个漏洞不需要竞争条件,成功率接近 100%。普通用户只需执行一段 732 字节的 Python 脚本,就能利用 algif_aead 模块将 /usr/bin/su 的内存改写。之后任何人在终端敲一个 su,回车,直接变 root

更让我后背发凉的是:所有主流发行版均无补丁。

上游在 4 月 1 日就修了,但因为协调披露流程,补丁还卡在发行版的 backport 环节。4 月 29 日漏洞被提前公开,各大厂商直接被打了个措手不及。

我当时的心情,像看到自家门锁被人挂到网上配了万能钥匙,而换锁的师傅还要好几天才能到。


二、验证

我立即在内网服务器部署了镜像,就是想亲自看看这个漏洞。

  • 测试机:Debian 13,内核 6.12.57+deb13-amd64(未修复状态)
  • 普通用户:testuser(无 sudo 权限)
  • 网络:已断开外网(内网隔离)

Copy Fail 的利用代码已经在 GitHub 上公开。我以 testuser 身份登录测试机:

$ git clone https://github.com/theori-io/copy-fail-CVE-2026-31431.git
$ cd copy-fail-CVE-2026-31431

随后验证文件完整性:

$ sha256sum copy_fail_exp.py
a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9  copy_fail_exp.py

接下来,直接执行脚本:

$ python3 copy_fail_exp.py
#

是的,脚本运行仅 2~3 秒,无报错、无卡顿,终端提示符瞬间从普通用户 $ 变为 root 权限 #

你不信?请执行 whoami 指令试试:

# whoami
root

我后背一凉。一个普通用户,一行 Python,三秒钟,直接拿到整个服务器的 root


三、封堵

验证完成,接下来是真正的工作,封堵

官方补丁还没出来,我不能坐等。临时缓解措施只有一条:让内核永远无法加载 algif_aead 模块。

1. 立即生效的封堵命令

切回 root 用户:

echo "install algif_aead /bin/false" > /etc/modprobe.d/block-algif.conf
rmmod algif_aead 2>/dev/null
update-initramfs -u

解释一下这三条命令:

  • install algif_aead /bin/false:告诉内核,任何试图加载 algif_aead 模块的操作,都执行 /bin/false(加载失败)。
  • rmmod algif_aead:如果模块已经加载,立即卸载(2>/dev/null 忽略错误)。
  • update-initramfs -u:将配置写入初始化内存盘,确保重启后依然生效。

2. 验证封堵是否有效

重启测试机(必须重启,因为页缓存中的脏数据还在):

reboot

重新以 testuser 登录,再次尝试利用:

$ python3 copy_fail_exp.py
Error: Module algif_aead not available
$ su
Password:   # 仍然需要密码,无法提权

封堵成功。


四、暴雨前的宁静

Copy Fail 封堵后的那几天,我每天都会检查一遍安全公告。官方补丁迟迟没出来,各大发行版的回答永远是“正在准备中”。

我一度以为,危机已经解除,只需要静候补丁就万事大吉了。服务器静悄悄地跑着,没有异常登录,没有 CPU 飙升,没有报警短信。

直到 5 月 7 日。

傍晚,群里又炸开了锅,又是一个 Linux 内核本地提权漏洞,名字叫 Dirty Frag。我点开链接,越看越心惊。

1. 它比 Copy Fail 更野

Dirty Frag 属于同一个漏洞家族(零拷贝路径 + splice() + 页缓存),但这次不是只改一个模块,而是 两个独立模块各有一个变体

变体模块权限要求攻击效果
ESPesp4 / esp6需要 user_namespace篡改任意只读文件的内存页(如 /usr/bin/su
RxRPCrxrpc完全不需要任何权限直接清空 /etc/passwdroot 的密码字段

两个变体互相覆盖对方的限制:如果你的内核不支持 user_namespace,ESP 变体失效,但 RxRPC 变体依然有效;反之如果 RxRPC 模块被禁用,ESP 变体也能单独完成提权。

官方公告里写着:单一攻击程序可在几乎所有主流 Linux 发行版上通用。

而且,当时所有发行版 均无补丁

为什么?上游在 5 月 7 日刚合并了 ESP 模块的修复,RxRPC 的修复还没影子。而正常的协调披露流程需要给发行版 14 天左右的 backport 时间,结果漏洞被第三方提前公开,利用代码直接上传到了 GitHub。

我登录生产服务器,心跳加速。

2. 我必须亲眼看到

跟上次一样,我先在内网测试机上验证。测试环境不变。

$ git clone https://github.com/v4bel/dirtyfrag.git
$ cd dirtyfrag
$ ls
exp.c  README.md  assets

编译:

$ gcc -o exp exp.c -lutil
$ ./exp
#

又是三秒,又是一个 #。我试了一下:

# whoami
root

更可怕的是 RxRPC 变体,它不需要创建用户命名空间,在默认封锁严格的系统上也能跑。我单独测试了 RxRPC 的利用:

$ ./exp_rxrpc   # 另一个预编译的变体
[+] Root password cleared, try 'su -'
$ su -
# 

我检查 /etc/passwd,发现 root: 变成了 root::——密码字段被清空了。

这时我才真正感到后怕。Copy Fail 好歹需要接触 algif_aead 模块,而 Dirty FragRxRPC 变体,完全不需要任何权限,任何一个能登录服务器的普通用户,一行命令,就能把 root 密码抹掉。

3. 双重封堵

我立刻登录生产服务器,先检查三个模块的状态:

lsmod | grep -E "esp4|esp6|rxrpc"
# 没有输出

然后用官方推荐的封堵命令,新建一个配置文件:

printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf
rmmod esp4 esp6 rxrpc 2>/dev/null
update-initramfs -u

这时我的 /etc/modprobe.d/ 目录下有两个封堵文件:

  • block-algif.conf:禁用 algif_aead(防 Copy Fail
  • dirtyfrag.conf:禁用 esp4esp6rxrpc(防 Dirty Frag

互不冲突,协同防御。


五、内核升级

两个漏洞都临时封堵了,但我心里清楚:禁用模块只是缓兵之计。真正的安全感,只能来自上游补丁。

5 月 8 日,Debian 仓库终于推送了 linux-image-6.12.85。我立刻查看 changelog

apt changelog linux-image-6.12.85+deb13-amd64 | grep -i "cve-2026-31431"

crypto: algif_aead - Revert to operating out-of-place (CVE-2026-31431)

Copy Fail 已经修复:官方通过回退(revert)的方式,彻底消除了 algif_aead 模块中的“原地操作”缺陷。这意味着即使模块被加载,也不会再造成提权。

Dirty FragRxRPC 部分,changelog 里没有任何相关字样。我再次确认:

apt changelog linux-image-6.12.85+deb13-amd64 | grep -i "rxrpc"
# 虽然有几十条 rxrpc 相关的修复,但没有一条是针对页缓存写入的补丁

也就是说,哪怕升级到最新内核,RxRPC 变体依然危险。我必须保留对 rxrpc 模块的禁用。

1. 执行升级

决定升级后,我执行了标准流程:

apt update
apt upgrade -y

升级过程中遇到了 OpenSSH 配置文件冲突。因为我之前修改过 /etc/ssh/sshd_config(改端口、禁止密码登录等)。我选择了 保留本地版本,继续升级。

升级完成后,确认新内核已安装:

dpkg -l | grep linux-image | grep 6.12.85
ii  linux-image-6.12.85+deb13-amd64  6.12.85-1  amd64  Linux 6.12 for 64-bit PCs
ii  linux-image-amd64                6.12.85-1  amd64  Linux for 64-bit PCs (meta-package)

2. 重启 + 验证

重启是必须的,否则新内核不会生效。

reboot

重新登录后:

uname -r
6.12.85+deb13-amd64

检查漏洞相关的所有模块:

lsmod | grep -E "esp4|esp6|rxrpc|algif_aead"
# 没有任何输出
  • algif_aead 没有加载——即使加载也不再有漏洞,但我保留着 /etc/modprobe.d/block-algif.conf,暂时没动。
  • esp4 / esp6 / rxrpc 依然被 dirtyfrag.conf 中的 install /bin/false 拦截。

我又用测试机验证了一遍升级后的效果:

  • Copy Failalgif_aead 可以被正常加载,但无法提权(内核已修复)。
  • Dirty Frag (ESP):由于新内核包含 ESP 补丁,即使不封堵也安全。
  • Dirty Frag (RxRPC):仍然危险,必须继续禁用 rxrpc

六、写在最后

从 4 月 30 日到 5 月 10 日,整整十一天。两个 0day,四次封堵,一次内核升级,无数次心跳加速。

我学到了三件事:

  1. 0day 的空窗期,没有补丁 ≠ 没有防御。 因此模块禁用是最古老、也最可靠的临时手段。只要业务不受影响,直接把危险模块 install /bin/false,比等补丁更管用。

  2. 任何配置修改,只有重启之后还能自动拉起所有服务,才算真正完成。我这次因为 PM2 未正确配置开机自启,导致博客服务中断——这是不该犯的低级错误。

  3. 运维笔记必须可复现。 只记录“我做了什么”是不够的,还要写下“别人照着做也能成功”。POC 的哈希、精确的命令、封堵前后的对比,缺一不可。

天亮之后,补丁会来,服务器会继续跑。但这份笔记会留下来,成为下一次风暴来临时的灯塔。

愿每一次 0day,你的防线都跑在攻击者前面。


本文所有命令已在 Debian 13 / 内核 6.12.57 上验证。

声明:本文所涉及的漏洞原理、复现步骤、利用代码,仅可用于内部授权安全测试、合规漏洞研究与加固演练。严禁私自用于未授权服务器入侵、非法越权操作等违规违法行为,违者需自行承担全部法律责任与相关后果!



本页目录