CVE-2023-3390 Linux 内核 UAF 漏洞分析与利用
字数 1930 2025-08-18 11:36:36
Linux内核UAF漏洞CVE-2023-3390分析与利用教学文档
漏洞概述
CVE-2023-3390是Linux内核netfilter子系统nftables组件中的一个use-after-free漏洞。该漏洞源于nf_tables_newrule()函数在异常处理分支中释放rule和其引用的匿名set时,未能正确设置set的状态为inactivate,导致批处理中后续请求仍能访问已被释放的set,最终可能导致双重释放(double free)问题。
漏洞背景知识
nftables简介
nftables是Linux内核中的新一代包过滤框架,取代了之前的iptables。它提供了更高效的规则处理和更灵活的规则配置方式。
相关数据结构
nft_rule: 表示nftables规则nft_set: 表示nftables集合nft_expr: 表示规则中的表达式
漏洞详细分析
漏洞触发路径
-
初始创建阶段:
- 通过
NFT_MSG_NEWSET创建set_A和set_B - 通过
NFT_MSG_NEWRULE创建rule #0,其中包含两个lookup表达式- 第一个lookup表达式正确引用set_A
- 第二个lookup表达式初始化失败
- 通过
-
错误处理阶段:
- 失败导致调用
nf_tables_rule_release() - 该函数释放两个lookup表达式,导致set_A被释放
- 但set_A的状态未被标记为inactivate
- 失败导致调用
-
后续规则创建:
- 创建rule #1导致set_B被释放
- 创建rule #2尝试通过
nft_set_lookup_byid查找set_A - 由于set_A未被标记为inactivate,仍能被找到并引用
-
批处理终止阶段:
nfnetlink_rcv_batch()调用__nf_tables_abort- 释放rule #2引用的set_A,导致set_A被双重释放
关键代码分析
static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlattr * const nla[])
{
// ...
err = nf_tables_newexpr(&ctx, &expr_info[i], expr);
if (err < 0) {
NL_SET_BAD_ATTR(extack, expr_info[i].attr);
goto err_release_rule; // 异常分支
}
// ...
err_release_rule:
nf_tables_rule_release(&ctx, rule);
// ...
}
nf_tables_rule_release()调用链:
void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule)
{
nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE);
nf_tables_rule_destroy(ctx, rule);
}
关键问题在于NFT_TRANS_RELEASE参数不会设置set的状态为inactivate:
void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding,
enum nft_trans_phase phase)
{
switch (phase) {
case NFT_TRANS_PREPARE:
if (nft_set_is_anonymous(set))
nft_deactivate_next(ctx->net, set); // [1] set->use--
return;
case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE:
set->use--;
fallthrough;
default:
nf_tables_unbind_set(ctx, set, binding,
phase == NFT_TRANS_COMMIT);
}
}
补丁分析
补丁修改了错误处理路径:
err_destroy_flow_rule:
if (flow)
nft_flow_rule_destroy(flow);
err_release_rule:
- nf_tables_rule_release(&ctx, rule);
+ nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
+ nf_tables_rule_destroy(&ctx, rule);
err_release_expr:
关键改进:
- 使用
NFT_TRANS_PREPARE让匿名set的状态设置为inactivate - 然后通过
nf_tables_rule_destroy释放rule及其引用的expr和匿名set - 由于set状态为inactivate,后续请求无法获取该set
漏洞利用技术
利用思路
-
内存布局准备:
- 分配多个msg队列,每个队列分配0x400和0x200大小的msg_msg
- 释放其中两个0x200的msg_msg
-
触发漏洞:
- 触发漏洞使A、B使用刚释放的两个msg_msg
- 再次分配3个0x200大小的msg_msg(0,1,2),分别占用A,B,A内存块
- msg_0和msg_2指向同一块内存
-
信息泄露:
- 释放msg_2,此时msg_0指向被释放的内存
- 使用msg_msgseg占位msg_2,控制m_ts泄露相邻msg_msg中的指针
- 利用泄露的地址劫持next指针实现任意地址读
-
内核地址泄露:
- 结合堆喷泄露pipe_buffer里的ops指针
- 计算内核镜像基地址
-
权限提升:
- 劫持ops做ROP
关键利用技术细节
-
msg_msg结构利用:
- 通过控制msg_msg的m_ts字段实现越界读
- 通过控制next指针实现任意地址读
-
CONFIG_DEBUG_LIST特性利用:
- 利用内核在检测到非法链表指针时不panic的特性
- 允许伪造链表指针而不导致内核崩溃
-
非对齐释放处理:
- 释放多个堆喷的堆块到freelist
- 避免内核申请非法内存块导致崩溃
替代利用方案
另一种利用方案将UAF转换为user_key_payload和nft_set的重叠:
- 利用user_key_payload泄露地址
- 篡改set->ops实现控制流劫持
防御建议
- 及时应用内核补丁
- 启用内核内存保护机制如KASAN、KPTI等
- 限制非特权用户使用nftables功能
- 考虑禁用CONFIG_DEBUG_LIST以阻断此类利用技术
总结
CVE-2023-3390展示了Linux内核中复杂的UAF漏洞利用技术,关键点包括:
- 批处理请求中的状态管理不当
- 利用内存分配器特性构造特定内存布局
- 结合多种内核对象实现信息泄露和权限提升
- 利用内核调试特性绕过安全检测
该漏洞的分析和利用过程为理解复杂内核漏洞提供了很好的案例,也展示了现代内核漏洞利用的精细技巧。