Linux内核提权(CVE-2024-1086)

Linux内核提权(CVE-2024-1086)

原创 Bre4dy 暗影安全 2024-04-01 16:19

0x00 漏洞简介

Linux
内核的
netfilter

nf_tables
组件中存在释放后使用漏洞,可被利用来实现本地权限提升。
nft_verdict_init()
函数允许在钩子判定中使用正值作为丢弃错误,因此当
NF_DROP
发出类似于
NF_ACCEPT
的丢弃错误时,
nf_hook_slow()
函数可能会导致双重释放漏洞。

0x01 漏洞详情

nf_hook_slow()
函数

该函数循环遍历链中的所有规则,并在NF_DROP
发出时立即停止评估(返回函数) 。

在NF_DROP
处理过程中,它释放数据包并允许用户使用设置返回值
NF_GET_DROPERR()

NF_ACCEPT
在处理时使用
drop
错误使函数返回
NF_DROP
。经过一系列分析后,发现了一个双重释放。

// looping over existing rules when skb triggers chainint nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
 const struct nf_hook_entries *e, unsigned int s){
unsigned int verdict;
int ret;
// loop over every rule
for (; s < e->num_hook_entries; s++) {
// acquire rule's verdict
verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);
switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT:
break;  // go to next rule
case NF_DROP:
kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP);
// check if the verdict contains a drop err
ret = NF_DROP_GETERR(verdict);
if (ret == 0)
ret = -EPERM;
// immediately return (do not evaluate other rules)
return ret;
// [snip] alternative verdict cases
default:
WARN_ON_ONCE(1);
return 0;
}
}
return 1;}
nf_hook_slow()内核函数,它迭代 nftables 规则。

当为 netfilter
挂钩创建判决
对象时,内核允许正丢弃错误。这意味着攻击用户可能会导致以下情况,即从钩子/
规则返回
nf_hook_slow()
时释放 skb
对象,然后返回,就像链中的每个钩子
/
规则都返回一样。这会导致调用者误解情况,并继续解析数据包并最终双重释放它。

// userland API (netlink-based) handler for initializing the verdict
static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
    struct nft_data_desc *desc, const struct nlattr *nla)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nlattr *tb[NFTA_VERDICT_MAX + 1];
struct nft_chain *chain;
int err;
// [snip] initialize memory
// malicious user: data->verdict.code = 0xffff0000
switch (data->verdict.code) {
default:
// data->verdict.code & NF_VERDICT_MASK == 0x0 (NF_DROP)
switch (data->verdict.code & NF_VERDICT_MASK) {
case NF_ACCEPT:
case NF_DROP:
case NF_QUEUE:
break;  // happy-flow
default:
return -EINVAL;
}
fallthrough;
case NFT_CONTINUE:
case NFT_BREAK:
case NFT_RETURN:
break;  // happy-flow
case NFT_JUMP:
case NFT_GOTO:
// [snip] handle cases
break;
}
// successfully set the verdict value to 0xffff0000
desc->len = sizeof(data->verdict);
return 0;
}

nft_verdict_init()
内核函数,构造一个
netfilter verdict
对象

// looping over existing rules when skb triggers chainint nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
const struct nf_hook_entries *e, unsigned int s){
unsigned int verdict;
int ret;
for (; s < e->num_hook_entries; s++) {
// malicious rule: verdict = 0xffff0000
verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);  
// 0xffff0000 & NF_VERDICT_MASK == 0x0 (NF_DROP)
switch (verdict & NF_VERDICT_MASK) {  
case NF_ACCEPT:
break;
case NF_DROP:
// first free of double-free
kfree_skb_reason(skb,
SKB_DROP_REASON_NETFILTER_DROP);  

// NF_DROP_GETERR(0xffff0000) == 1 (NF_ACCEPT)
ret = NF_DROP_GETERR(verdict);  
if (ret == 0)
ret = -EPERM;

// return NF_ACCEPT (continue packet handling)
return ret;  
// [snip] alternative verdict cases
default:
WARN_ON_ONCE(1);
return 0;
}
}
return 1;}

nf_hook_slow()
内核函数,它迭代
nftables
规则

static inline int NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk,
struct sk_buff *skb, struct net_device *in, struct net_device *out,
int (*okfn)(struct net *, struct sock *, struct sk_buff *)){
// results in nf_hook_slow() call
int ret = nf_hook(pf, hook, net, sk, skb, in, out, okfn);
// if skb passes rules, handle skb, and double-free it
if (ret == NF_ACCEPT)
ret = okfn(net, sk, skb);
return ret;}

NF_HOOK()
内核函数,成功时调用回调函数



释放会影响slab
缓存
struct sk_buff
中的对象skbuff_head_cache
,以及动态大小的
sk_buff->head
对象,范围从
kmalloc-256
直接来自伙伴分配器的最多
4
个页面(
65536
字节)与
ipv4
数据包 。

该sk_buff->head
对象
kmalloc_reserve()
通过
__alloc_skb()

这允许我们分配动态大小的对象。因此,我们可以从分配器分配大小从 256

65536
字节的完整页面的
slab
对象。

漏洞详见:
https://pwning.tech/nftables/

0x02
影响版本

该漏洞影响从(包括)
v5.14
到(包括)
v6.6
的版本,不包括修补分支
v5.15.149>

v6.1.76>

v6.6.15>
。这些版本的补丁于
2024

2
月发布。底层漏洞影响从
v3.15

v6.8-rc1
的所有版本(不包括已修补的稳定分支)。

0x03 漏洞验证

验证环境:
ubuntu 23.04

0x04参考链接

https://github.com/Notselwyn/CVE-2024-1086