漏洞描述
Linux 内核 RxRPC 子系统中的 rxgk 模块被发现存在一个高危漏洞。问题出在 rxgk_verify_response() 函数中,它对 auth_len 的边界检查写反了方向。本该被拦截的超大 RESPONSE 认证器就这样被悄悄放行,导致受污染的数据流入了 rxgk_decrypt_skb()。更致命的是,该函数在进行 AEAD 原地解密时,完全没有执行 COW 保护检查,直接将解密结果写回了只读的页缓存页面。
漏洞的核心风险点在于:解密操作先于 HMAC 校验执行。这意味着,即便后续 HMAC 校验失败,页缓存中的数据也早已被篡改。攻击者可以利用这一缺陷,构造一个精心设计的交错 SGL,将目标 SUID 文件的页缓存替换为一段 192 字节的 ELF shellcode。之后,只要执行这个被篡改的文件,即可获取 root shell。
影响版本
并非所有系统都受影响,此漏洞仅在启用了 CONFIG_RXGK 的内核上触发。像 Fedora 各版本、Arch Linux、openSUSE Tumbleweed 等发行版默认开启此选项,建议相关用户立即升级内核。使用主线内核 PPA 或 ELRepo 的 kernel-ml 的系统也应保持警惕。
相反,默认不启用 RxGK 的发行版(如 Debian Stable、RHEL 8/9、Ubuntu LTS)通常不受影响。
您可以执行以下命令快速自查:
zcat /proc/config.gz | grep CONFIG_RXGK
uname -r
如果输出中包含 CONFIG_RXGK=y,并且内核版本早于 6.8.12,请务必尽快更新。
漏洞详情与利用思路
整个漏洞的利用 POC 分为三个核心步骤。如果不了解底层的页缓存机制,可以看看 云栈社区 上的相关讨论。
第一步:伪造密钥注册
攻击者首先生成一个随机密钥 K,并将其注册进内核的 keyring 中。这样,当 rxrpc 的内核工作线程查询服务器密钥时,就能找到这条看似“合法”的记录,为后续的认证绕过铺平道路。
snprintf(desc, sizeof(desc), "%u:6:%u:%u", SVC_ID, KVNO, ENCTYPE);
key_serial_t k = key_add("rxrpc_s", desc, SERVER_SECRET, KEY_LEN, kr);
第二步:构造交错内存布局
这一步非常巧妙。攻击者利用 pipe、vmsplice 和 splice 系统调用,精心构造了一个交错的 SGL。这个 SGL 能让 skb 的 frag 页面在匿名页和目标文件的物理页之间交替排列。相关技术的入门知识可以在 安全/渗透/逆向 板块找到。
vmsplice(pfd[1], &user_buf, 1, 0); /* 匿名页 → skb frag */
splice(tfd, &off, pfd[1], NULL, 16, 0); /* 文件页 → skb frag */
splice(pfd[0], NULL, udp, NULL, total, 0); /* pipe → UDP socket */
这个精心编排的布局之后会被 skb_to_sgvec() 直接传递给 AEAD 解密。解密操作的输出会就地覆盖到文件页上。即使 HMAC 校验最终失败并终止了此次连接,目标文件的页缓存也已经被污染,木已成舟。
第三步:植入 payload 并执行
攻击分两批将 192 字节的 ELF payload 写入目标文件的页缓存。这段 payload 实际上是 x86_64 的 shellcode,功能非常直接:先调用 setuid(0) 提升权限,然后执行 execve("/bin/sh") 获得 root shell。污染完成后,直接执行目标 SUID 程序即可。
execl(target, target, (char *) NULL);
POC 代码可在以下公开仓库中找到:
- Delphos-Labs/disclosures · DirtyCBC
- v12-security/pocs · dirtydecrypt