论坛首页 安全编程开发区 阅读主题

[原创]The shadow over Netfilter: 新一代脏页表利用技巧-CVE-2024-1086

451 浏览 0 回复
#1 楼主 2026-06-01 21:09:06
依本人之见,这 CVE-2024-1086,乃是潜藏于 Linux 内核深处,那名为 netfilter 的古老机制(?)中,一处令人不安的裂隙。它并非来自外域的邪神,而是源自内部,那本应秩序井然的内存管理,在某些特定、扭曲的条件下,竟会陷入一种可怖的“用后释放” (Use-After-Free) 状态。
其本质,在于 netfilter 的 nf_tables 组件在处理规则(rules)的垃圾回收和删除时,未能完全斩断其与内存的联系。这就像是,一个本应被彻底遗忘的实体,其幽灵却在内存的深渊中徘徊,等待着被恶意的意志所唤醒。当这幽灵被重新占据,其原有的结构被篡改,便能赋予凡人以僭越神祇的权能——从一个卑微的本地用户,跃升为掌控整个系统的至高存在。这并非寻常的错误,而是一种对底层秩序的亵渎,一种对内存生命周期的扭曲。它揭示了,即使在最坚固的数字堡垒中,亦有其脆弱、可被腐化的角落,足以让混沌的低语
渗透进来,将控制权拱手让与那些窥伺已久的黑暗存在。其影响,正如那无形之触,悄然伸向系统的核心,将权限的锁链一一解开,直至整个世界都暴露在无尽的深渊之前。
------------ Gemini-2.5-flash该漏洞是一个netfilter中处理HOOK函数时导致的Double Free 释放漏洞,博客涉及了较新(大概)的漏洞利用技术dirty pagetable,利用ip分片机制来无限扩大时间片并且可以控制skb释放时间的技巧,以低特权刷新tlb等技巧。环境以exp位于我的github仓库,包含rootfs和bzImage,一键启动
linux kernel: linux-6.3.4
rootfs: busybox
内核编译配置需要选中以下选项本节大部分的知识来源于Linux kernel doc
他用来表示一个网络流量包在内核中的数据结构如下:[!NOTE]
这个结构体专门用来存放元数据,对于网络包的数据则存放在其他缓冲区当中而sk_buff.head指向主要的head buffer,而这个head buffer分为两个部分Netfilter是一种linux内核网络过滤器
Netfilter包含几种table(struct xt_table),每个table用来存储不同的配置信息
每个table有多个chain(struct xt_table_info), chain表示对报文的拦截点,就比如一个网络层ipv4报文传过来,他会对每个拦截点进行检测,也就是每条chain
而每个chain则包含一些rule(struct ipt_entry),一条rule则包含一个或多各正则匹配规则(match),和一个执行动作
其拥有以下几种功能(table):这个结构体就是上述的表table,存在一个private字段,类型为struct xt_table_info且添加了__rcu的标识,这个标识表示在读取的时候不用加锁,
但在写的时候更新数据这里的entries的每个字段则存放了每个cpu所对应的专属buf,如下而每个CPU bufs里面包含的内容则是一个个chains数组然后每个chains里面则包含了一条条rules那么由于每个chains里面的rule条数都可能不同,所以需要还存在一定的偏移字段
所以struct xt_table_info.hook_entry[]里面就存的是在cpu bufs里面每个chains的起始偏移
这样就可以精准定位到每个chains下的rule
然后由于这里还存在一个默认规则字段,所以在对应的struct xt_table.underflow[]则存放的是每个chains的默认rule的相对偏移然后每条rule是使用sturct ipt_entry来表示而每一条rule包含多个匹配规则struct xt_entry_match和一个执行动作struct xt_entry_targetnetfilter通过setsockopt, getsockopt来进行用户-内核的交互,
在此基础上nftables实现了自己的一个框架,允许不同的防火墙来实现自己和用户空间的通信函数
这里主要涉及了nf_register_sockopt()函数将nf_sockopt_ops结构体实例注册到netfilter管理的全局链表当中
注册完毕就可以调用nf_sockopt_find()来查找对应的nf_sockopt_ops用来表示数据包的处理指令下面的则是netfilter的hook时机[!NOTE]
在调试时,开启netfilter的情况下,向自身主机发送ip头dst_addr=255.255.255.255, src_addr=1.1.1.1,
socket系统调用中sock_addr=127.0.0.2的环回地址的情况下,经过的HOOK点顺序是NF_INET_LOCAL_OUT, NF_INET_POST_ROUTING, NF_INET_PRE_ROUTING, 这里在后面的ip发包在调试过程中会有更详细的讲解这两个库实际上是方便用户来编写netfilter的rules,还有通过netlink来访问内核提供的NFTABLES板块,可以直接从官网获取源码然后自己编译构造IP包发送,需要用到两种系统调用,分别是socket, sendto
socket系统调用用来构建套接字socket, 套接字用来收发数据,并且与内核sock进行关联
sendto则利用socket传回的fd来发送信息这里的SOCK_RAW表示我们自己构造IP头部用户使用sendto向指定地址发送消息的时候,会首先调用内核系统调用__x64_sys_sendto
在本次漏洞利用中我们是构造了RAW_INET包,该flag表示我们是想要由自身来提供头部信息
这里大致介绍一下在sendto系统调用的流程中,执行流在内核中的旅行路线,这里将主要聚焦于netfilter hook点所以,如果我们发送一个数据包分片的时候,经过的netfilter hook点顺序可能是
NF_INET_LOCAL_OUT -> NF_INET_POST_ROUTING -> NF_INET_PRE_ROUTING -> NF_INET_LOCAL_IN漏洞出自于nf_hook_slow()在switch case 语句中NF_DROP的选项,这是由于当用户所设计的netfilter hook函数最后返回NF_DROP时即将执行的程序流程这里的流程将会首先释放这个skb,但是这里程序再次判断了NF_DROP_GETERR来获取返回参数,
这就给了用户一定的操作空间,如果可以通过这个函数将ret修改为NF_ACCEPT, 也就是1,
那么当这个函数返回后将回到下面的nf_hook()函数nf_hook()函数返回1则会导致调用后续的okfn(),这里使用ip_forward()进行举例
该函数将在最后调用NF_HOOK()函数而NF_HOOK()函数将会根据nf_hook()函数的返回值来决定是否调用okfn参数指针所指向的地址
返回值为1则说明hook函数处理的返回值为NF_ACCEPT那么就能在之后对skb进行二次释放,因此导致了doub

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-287573.htm

暂无回复,快来抢沙发吧!

请登录后参与讨论

立即登录 注册账号