(本文写于2025年5月17日。没想到后来crusaders of rust
团队又找到了一种触发方式,exp已经公开(CVE-2025-38001) Exploiting All Google kernelCTF Instances And Debian 12 With A 0-Day For $82k: A RBTree Family Drama (Part One: LTS & COS)
应该和这里的方法差不多)
该漏洞实际有三个CVE
,对应三种不同的触发方式:
- 利用
hfsc
和netem
的组合。 - 利用
hfsc_enqueue
的toctou
漏洞。 - 利用
hfsc_dequeue
。
本文主要分析的是第一种组合,在此基础上提供一种利用的思路。
影响
影响5.0
往后的所有未patch
内核版本。利用在6.6
内核上进行测试,其他内核版本利用也是可行的,可能需要做一下适配。
攻击者在开启了CONFIG_NET_NS的机器上(一般服务器都会默认开启)可以实现权限提升。不需要额外的安装或者配置。
漏洞成因分析和利用思路
漏洞成因是由于hfsc_enqueue
中对netem_enqueue
的调用反过来又调用自身,导致了重入的执行路径,在插入红黑树时会把该class
插入两次,释放之后会残留一个悬挂的指针。
可以在UAF
的基础上构建堆泄漏和地址写原语。该漏洞会对已经被free
掉的一个对象执行红黑树的插入操作。攻击者可以通过堆喷来控制uaf
对象,此时可以泄漏插入的对象的内核堆地址。更进一步,攻击者可以通过泄漏出的内核指针来伪造一个红黑树的节点,从而篡改指定位置的数据。
本文的利用环节通过红黑树插入操作往msg_msg
的next
字段写一个指针,将该uaf
转换成一个更强大的 double free
原语。利用double free
,攻击者可以利用一个可控的对象去控制另一个分配在同样地址区域的重要内核数据结构,本文使用的是usma
的利用方法,该利用可以任意修改内核数据和只读代码段(即可以patch
代码段,无效化很多防御措施),可以给攻击者实现权限提升或者植入恶意rootkit
。
具体利用方案
漏洞作者的exp尚未公开(更新:7月11日已经公开),这里提供的是一种可能的利用方案。
首先分配hfscclass,某一个class是uaf对象,指定了netem。
free掉uaf对象并分配keyctl,此时new一个hfscclass,keyctl的读可以泄漏该class的指针。同时释放掉其他keyctl减少配额压力。这里需要crosscache喷hfscclass(keyctl由于非root有限额,因此无法做堆喷对象),用两个进程pipe通信,防止class的层级互相影响。
删除掉刚才的class,并进行crosscache释放掉slab页面,堆喷msgmsg。 更新class1的data,使其指向已知地址的msgmsg的16字节位置,以伪造红黑树节点。这样红黑树的插入就能写入一个内核指针。注意由于刚刚执行了crosscache的free,此时partial slab很多不利于keyctl的更新,可以提前消耗掉这些slab。
此时,分配一个uaf的hfscclass。其会把自己的vtnode地址写入到msgmsg的next字段。由于hfscclass删除操作限制比较多,首先删除掉该hfscclass,喷keyctl。然后利用前面msgmsg去错位free掉hfscclass,此时分配keyctl,会在错位位置上。释放同时读取keyctl的函数指针,泄漏kaslr。此时分配usma的pgv,释放keyctl,再次分配keyctl以更新usma。
最后,我们已经有了一个能够将任意内核地址映射成可写页面的原语。一种方法是修改modprobe_path来进行提权,也可以往内核函数写shellcode。
利用效果
Limits
# cat /sys/kernel/slab/kmalloc-1k/objs_per_slab
16
如果内存高于16G
:
❯ sudo cat /sys/kernel/slab/kmalloc-1k/objs_per_slab
32
如果是大内存机器那么该参数就会为32
,大大降低堆喷的成功率。考虑到keyctl
本身存在限额,在大内存机器上实现利用可能还需要修改很多东西,这里出于poc
的目的就不再继续探索。