"Copy Fail" 是 Linux 内核 authencesn 加密模板中的一个严重逻辑漏洞。它允许非特权本地用户对系统上任何可读文件的页缓存执行确定性的、可控的 4 字节写入。通过针对 setuid 二进制文件(如 /usr/bin/su),攻击者可以修改内存中的执行缓存,从而将权限提升至 Root(UID 0)。
与 "Dirty Cow" 或 "Dirty Pipe" 等旧漏洞不同,Copy Fail 是一个直线型逻辑缺陷,触发时无需竞态条件、重试或易崩溃的时间窗口。它具有高度的可移植性和隐蔽性,因为只修改内存中的页缓存,而磁盘上的文件完全保持不变,从而绕过了标准的文件完整性监控工具。
该漏洞存在于三个不同内核组件的交汇处:
splice() 系统调用: splice() 系统调用在不复制的情况下在文件描述符和管道之间传输数据,通过引用传递页缓存页。当用户将文件(如 /usr/bin/su)拼接(splice)到 AF_ALG 套接字时,套接字的输入分散列表持有该文件内核缓存页的直接引用。authencesn 临时写入: authencesn 算法(用于 IPsec 扩展序列号)需要重新排列字节。为此,它临时将 4 字节的序列号作为"临时空间"写入输出缓冲区。然而,它写入的位置超出了合法的输出边界。由于 2017 年的就地优化,输出分散列表包含通过 splice() 传递的只读页缓存页。当 authencesn 写入超出输出边界时,它会直接覆盖目标文件缓存内核内存中的 4 个字节。
攻击者可以通过以下步骤利用此漏洞:
AF_ALG 套接字,并绑定到 authencesn(hmac(sha256),cbc(aes))。sendmsg(),其中包含携带攻击者想要写入的 4 字节的关联认证数据(AAD)负载。splice() 将目标文件(/usr/bin/su)通过管道传入套接字。偏移量和长度精确定义了 4 字节将被写入页缓存的哪个位置。recv() 触发解密操作,执行越界临时写入,直接写入目标文件的页缓存。execve("/usr/bin/su"))。内核执行包含注入的恶意 shellcode 的篡改页缓存版本,从而授予 root 访问权限。如果无法立即修补或重启内核,可以通过将相关 af_alg 模块全部加入黑名单并从内存中卸载来缓解此漏洞。
要阻止这些模块,请执行以下命令:
# 1. 如果模块当前已加载,则从内存中卸载
sudo modprobe -r algif_hash algif_skcipher algif_aead algif_rng af_alg
# 2. 将模块添加到黑名单
echo -e "blacklist af_alg\nblacklist algif_hash\nblacklist algif_skcipher\nblacklist algif_aead\nblacklist algif_rng" | sudo tee /etc/modprobe.d/stop-exploit.conf
# 3. 完全阻止 af_alg 模块被加载
echo "install af_alg /bin/true" | sudo tee -a /etc/modprobe.d/stop-exploit.conf
# 4. 重启系统以确保更改完全生效
sudo reboot
Linux 内核安全团队已修补此漏洞(提交:a664bf3d603d)。该补丁将 AF_ALG AEAD 操作恢复为异地(out-of-place)模型,将源分散列表和目标分散列表分离。这防止了页缓存页暴露给可写的目标分散列表。
所需操作: 将您的发行版内核更新为供应商提供的最新版本(Ubuntu、Amazon Linux、RHEL、SUSE 等),然后重启系统。