@
andlp 换个好点的 ai 吧。。
1. 核心触发原语:AF_ALG 与特定加密算法
脚本开头使用了 a = s.socket(38, 5, 0)。其中 38 对应的是 AF_ALG ( Linux Kernel Crypto API 的用户态接口)。
接着它绑定了特定的加密算法:a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))。
algif_aead 是内核中处理 AEAD (认证加密)的核心模块。
authencesn 是一种用于 IPsec 的加密包装器,它需要处理扩展序列号( ESN )。在计算 HMAC 时,它需要对序列号的字节进行重新排列,这会导致它在目标缓冲区中执行一次 4 字节的临时写入( Scratch Write )。
2. 内存越权:splice 与页缓存投毒
脚本中使用了 os.splice (对应 C 语言的 splice() 系统调用)。splice 可以在两个文件描述符之间移动数据,而不需要将数据复制到用户空间(即零拷贝)。
在这个 payload 中,攻击者通过 splice 将目标文件(这里是高权限的可执行文件 /usr/bin/su )映射到了加密套接字( Socket )的内存空间中作为“密文”输入。
漏洞的致命点在于:algif_aead 模块在执行加密操作时,默认是 “原地操作”( in-place ) 的(即源缓冲区和目标缓冲区是同一个)。当输入数据是通过 splice 从普通文件映射过来时,目标散列表( Scatterlist )实际上直接指向了该文件在内核中的 页缓存( Page Cache )。
3. 利用过程:积少成多的 4 字节写入
当脚本调用 u.recv() 触发解密操作时,底层的 authencesn 算法会将攻击者通过 sendmsg 传入的 4 字节序列号( seqno_lo ,即 payload 中的恶意指令片段),直接覆盖写入到由于原地操作而共享的“目标缓冲区”中。
因为目标缓冲区就是 /usr/bin/su 的页缓存,这就导致内核的只读页缓存被直接篡改了 4 个字节。
payload 中的 while i<len(e): c(f,i,e[i:i+4]); i+=4 是一个循环。它将一大段经过 zlib 压缩的 Shellcode (提权恶意代码)解压后,每次 4 个字节,利用上述机制一点点“缝合”进内核中 /usr/bin/su 的内存映像里。
4. 提权执行
当 4 字节循环写入完成后,内核中缓存的 /usr/bin/su 已经被注入了恶意的 Shellcode 。
此时脚本执行 g.system("su")。由于 Linux 内核会优先从页缓存中读取文件执行,加上 su 本身带有 setuid 属性(执行时拥有 root 权限),被投毒的 Shellcode 就会以 root 权限运行,从而完成提权
------
3. Linux 本该有的保护机制去哪了?(漏洞的真正命门)
是的,Linux 有一个极其核心的机制:内存权限控制( Memory Management Permission )。
在这个漏洞场景中,攻击者是用只读( Read-Only )权限打开的 /usr/bin/su 。
按照 Linux 正常的逻辑,当 authencesn 算法试图把那 4 字节的脏数据写到 /usr/bin/su 的页缓存时,内存管理系统( MM subsystem )应该立刻跳出来大喊:“停下!这个页面是只读的!”然后触发一个缺页异常( Page Fault ),直接把操作干掉,甚至把当前的进程杀掉( Segmentation Fault )。
如果这个机制生效,那 4 字节根本写不进去!
那为什么没生效呢?这恰恰是这个漏洞( CVE )最核心的代码 Bug 所在:
内核的 algif_aead 模块在处理 splice 传过来的内存页( Page )时,它底层调用的是 kmap_atomic 之类的底层函数去直接映射物理内存。
这个底层的写入操作绕过了 VFS (虚拟文件系统)的写权限检查,也绕过了正常的 Copy-on-Write (写时复制)机制。它盲目地假设:“既然你把这个缓冲区指定为加密/解密的输出目标( dst ),那它一定在前面已经被检查过是可写的了。”