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: 表示规则中的表达式

漏洞详细分析

漏洞触发路径

  1. 初始创建阶段:

    • 通过NFT_MSG_NEWSET创建set_A和set_B
    • 通过NFT_MSG_NEWRULE创建rule #0,其中包含两个lookup表达式
      • 第一个lookup表达式正确引用set_A
      • 第二个lookup表达式初始化失败
  2. 错误处理阶段:

    • 失败导致调用nf_tables_rule_release()
    • 该函数释放两个lookup表达式,导致set_A被释放
    • 但set_A的状态未被标记为inactivate
  3. 后续规则创建:

    • 创建rule #1导致set_B被释放
    • 创建rule #2尝试通过nft_set_lookup_byid查找set_A
    • 由于set_A未被标记为inactivate,仍能被找到并引用
  4. 批处理终止阶段:

    • 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:

关键改进:

  1. 使用NFT_TRANS_PREPARE让匿名set的状态设置为inactivate
  2. 然后通过nf_tables_rule_destroy释放rule及其引用的expr和匿名set
  3. 由于set状态为inactivate,后续请求无法获取该set

漏洞利用技术

利用思路

  1. 内存布局准备:

    • 分配多个msg队列,每个队列分配0x400和0x200大小的msg_msg
    • 释放其中两个0x200的msg_msg
  2. 触发漏洞:

    • 触发漏洞使A、B使用刚释放的两个msg_msg
    • 再次分配3个0x200大小的msg_msg(0,1,2),分别占用A,B,A内存块
    • msg_0和msg_2指向同一块内存
  3. 信息泄露:

    • 释放msg_2,此时msg_0指向被释放的内存
    • 使用msg_msgseg占位msg_2,控制m_ts泄露相邻msg_msg中的指针
    • 利用泄露的地址劫持next指针实现任意地址读
  4. 内核地址泄露:

    • 结合堆喷泄露pipe_buffer里的ops指针
    • 计算内核镜像基地址
  5. 权限提升:

    • 劫持ops做ROP

关键利用技术细节

  1. msg_msg结构利用:

    • 通过控制msg_msg的m_ts字段实现越界读
    • 通过控制next指针实现任意地址读
  2. CONFIG_DEBUG_LIST特性利用:

    • 利用内核在检测到非法链表指针时不panic的特性
    • 允许伪造链表指针而不导致内核崩溃
  3. 非对齐释放处理:

    • 释放多个堆喷的堆块到freelist
    • 避免内核申请非法内存块导致崩溃

替代利用方案

另一种利用方案将UAF转换为user_key_payload和nft_set的重叠:

  1. 利用user_key_payload泄露地址
  2. 篡改set->ops实现控制流劫持

防御建议

  1. 及时应用内核补丁
  2. 启用内核内存保护机制如KASAN、KPTI等
  3. 限制非特权用户使用nftables功能
  4. 考虑禁用CONFIG_DEBUG_LIST以阻断此类利用技术

总结

CVE-2023-3390展示了Linux内核中复杂的UAF漏洞利用技术,关键点包括:

  1. 批处理请求中的状态管理不当
  2. 利用内存分配器特性构造特定内存布局
  3. 结合多种内核对象实现信息泄露和权限提升
  4. 利用内核调试特性绕过安全检测

该漏洞的分析和利用过程为理解复杂内核漏洞提供了很好的案例,也展示了现代内核漏洞利用的精细技巧。

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被双重释放 关键代码分析 nf_tables_rule_release() 调用链: 关键问题在于 NFT_TRANS_RELEASE 参数不会设置set的状态为inactivate: 补丁分析 补丁修改了错误处理路径: 关键改进: 使用 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漏洞利用技术,关键点包括: 批处理请求中的状态管理不当 利用内存分配器特性构造特定内存布局 结合多种内核对象实现信息泄露和权限提升 利用内核调试特性绕过安全检测 该漏洞的分析和利用过程为理解复杂内核漏洞提供了很好的案例,也展示了现代内核漏洞利用的精细技巧。