FlawOpen

flawopen.com/Teardowns/cve-2024-1086-linux-netfilter-nftables-uaf

● CVE-2024-1086 · CVSS 7.8 · 高危
安全研究 · FlawOpen

CVE-2024-1086:Linux nf_tables 释放后使用

CVE-2024-1086 是 Linux nf_tables 的释放后使用漏洞,原因是接受了无效的 DROP 参数。请安装发行版提供的修复内核。

💡 通俗易懂的原理解析 (ELI5)

想象一张表单,工作人员只能选择“接受”或“丢弃”。另有一个字段填写丢弃操作的错误码,只允许零或有效的负错误码。存在漏洞的校验逻辑让正数“接受”值进入了这个字段,后续网络代码因此对同一判定产生不一致的解释。补丁只接受准确、受支持的判定值,从入口处拒绝其他值。

核心概念与专有名词

nf_tables
Linux 内核子系统,nftables 使用它配置数据包过滤及相关网络规则。
Netfilter 判定
内核评估数据包规则后的结果,例如 NF_ACCEPT 或 NF_DROP。DROP 可以携带错误值,hook 期望其为零或有效的负 errno。
释放后使用(CWE-416)
对象生命周期结束后,代码仍访问该对象的内存安全缺陷。NVD 将本漏洞记录为本地内核提权。
User namespace
用于映射进程身份和能力的 Linux 命名空间。是否允许非特权用户创建取决于内核及发行版策略;这本身不代表一定能逃逸到宿主机。

框架映射

根本原因剖析 (Root Cause)

在 net/netfilter/nf_tables_api.c 中,nft_verdict_init() 过去会屏蔽判定值,并允许 NF_DROP 或 NF_QUEUE 携带参数。Netfilter hook 要求 NF_DROP 的高位包含零或有效的负 errno。上游修复说明,像 NF_ACCEPT 这样的正值可能导致释放后使用。补丁移除了宽松的处理路径,只接受精确的受支持判定;无效值返回 -EINVAL。NVD 将影响描述为本地提权。能否触达该路径取决于内核、可用能力和发行版策略;不能假定所有容器配置都具有相同风险。

攻击执行流程分解

步骤 1

具备本地规则管理能力

已记录的攻击需要本地访问。进程必须能够进入 nf_tables 判定校验路径;所需能力以及是否允许非特权 user namespace 取决于主机配置。

步骤 2

无效判定参数进入校验

修复前,nft_verdict_init() 在应用 NF_VERDICT_MASK 后会接受某些带参数值,包括参数位中的正值 NF_ACCEPT。

步骤 3

hook 路径触发释放后使用

Netfilter hook 将 NF_DROP 参数解释为零或有效的负 errno。上游报告指出,被接受的正值可能在数据包处理时导致释放后使用;补丁没有证明通用利用原语或必然的容器逃逸。

步骤 4

安装发行版修复内核

上游更改会拒绝不受支持的判定参数。请安装并启动发行版提供的修复内核,因为各发行版的软件包版本和回移补丁不同。

源代码对比:漏洞与安全实现

漏洞代码屏蔽判定值后继续处理,因此像正值 NF_ACCEPT 这样的参数可能进入 NF_DROP 的错误字段。修复只允许精确常量,其他值均返回 -EINVAL。以下是上游补丁中的针对性代码片段,并非可独立编译的完整函数。

源码摘录: net/netfilter/nf_tables_api.c

存在漏洞的实现
/* f342de4e2f33 之前 net/netfilter/nf_tables_api.c 中 nft_verdict_init() 的代码片段。
 * 带掩码值的路径接受了带参数的 verdict。 */
switch (data->verdict.code) {
default:
    switch (data->verdict.code & NF_VERDICT_MASK) {
    case NF_ACCEPT:
    case NF_DROP:
    case NF_QUEUE:
        break;
    default:
        return -EINVAL;
    }
    fallthrough;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
    /* 后续处理其他已有的 verdict。 */
    break;
}
加固后的安全修复
/* f342de4e2f33 修改后的 net/netfilter/nf_tables_api.c 中
 * nft_verdict_init() 的代码片段。 */
switch (data->verdict.code) {
case NF_ACCEPT:
case NF_DROP:
case NF_QUEUE:
    break;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
    /* 后续处理其他已有的 verdict。 */
    break;
default:
    return -EINVAL;
}

工程与系统安全加固清单

参考来源