头图

前言

本文将介绍如何绕过KASLR以及如何提权利用。

KASLR绕过

可以利用byteorder操作加上netlink组订阅可以泄露rule中的handle字段。该方法应该是可以用来泄露kernel基地址的,但是作者还提出另一种方法进行泄露。应该是为了提权利用做铺垫。

由于发现已经泄露的模块的基地址,因此可以利用模块地址伪造表达式。

作者找到了range表达式,用于伪造其余表达式。总大小为0x23。并且表达式是八字节对齐的,因此该结构体会占用0x28字节。

struct nft_range_expr {
    struct nft_data        data_from;
    struct nft_data        data_to;
    u8            sreg;
    u8            len;
    enum nft_range_ops    op:8;
};

具体的布局如下

image-20240227185357673

可以看到data_fromdata_to都是从用户态中传递过去的数据,因此我们可以在这些区域内伪造表达式,这有点像在CTF中,我们泄露了堆块基址后,随意伪造堆块。

由于我们有0x28字节的空间,但是实际能够操作的空间是data_fromdata_to两段,即0x20的空间大小。因此我们需要挑选小于0x20的规则表达式进行伪造,并且能够执行泄露功能的。

这里作者选用了byteorder表达式,可以看到该表达式在对齐后只占用八字节。

struct nft_byteorder {
    u8            sreg;
    u8            dreg;
    enum nft_byteorder_ops    op:8;
    u8            len;
    u8            size;
};

构造后,可以发现还有八字节的data_to没有用,但是并不能直接丢弃不适用,因为在调用完byteorder操作后还需要继续执行其他规则表达式。

image-20240227190243722

但是其他表达式都是需要大于0x8的,毕竟一个操作指针就占用八字节了,此时作者选用了meta表达式。可以看到meta表达式也只用到了三个字节,刚好对应range表达式的sreglen以及op

struct nft_meta {
    enum nft_meta_keys    key:8;
    u8            len;
    union {
        u8        dreg;
        u8        sreg;
    };
};

meta表达式的操作如下,在meta表达式中meta->key执行具体的操作,如[1],但是若该值是非法值则会执行[2],可以看到该meta表达式仅会抛出异常,但是不会终止运行,这就说明即使meta->key是非法值也不会影响后续规则表达式的正常执行。

File: linux-5.19\net\netfilter\nft_meta.c
418: void nft_meta_set_eval(const struct nft_expr *expr,
419:                struct nft_regs *regs,
420:                const struct nft_pktinfo *pkt)
421: {
422:     const struct nft_meta *meta = nft_expr_priv(expr);
423:     struct sk_buff *skb = pkt->skb;
424:     u32 *sreg = &regs->data[meta->sreg];
425:     u32 value = *sreg;
426:     u8 value8;
427: 
428:     switch (meta->key) { ----> [1]
429:     case NFT_META_MARK:
430:         skb->mark = value;
431:         break;
432:     case NFT_META_PRIORITY:
433:         skb->priority = value;
434:         break;
435:     case NFT_META_PKTTYPE:
436:         value8 = nft_reg_load8(sreg);
437: 
438:         if (skb->pkt_type != value8 &&
439:             skb_pkt_type_ok(value8) &&
440:             skb_pkt_type_ok(skb->pkt_type))
441:             skb->pkt_type = value8;
442:         break;
443:     case NFT_META_NFTRACE:
444:         value8 = nft_reg_load8(sreg);
445: 
446:         skb->nf_trace = !!value8;
447:         break;
448: #ifdef CONFIG_NETWORK_SECMARK
449:     case NFT_META_SECMARK:
450:         skb->secmark = value;
451:         break;
452: #endif
453:     default:
454:         WARN_ON(1); ---->[2]
455:     }
456: }

因此第二个伪造的表达式也找到了,就是meta表达式。由于我们直接伪造了规则表达式,因此不会进行寄存器参数的校验,只要选择内核地址选择泄露即可。

image-20240227191748571

这里简单说一下伪造的规则头,此时的len需要设置为0x20以及islast需要设置为0。

最后泄露的效果如下,即使内核已经抛出了异常,但是不会影响后续表达式的正常执行。

image-20240227192131407

【----帮助网安学习,以下所有学习资料加vx:dctintin,备注“思否”获取!】
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC漏洞分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

提权利用

既然可以随意伪造表达式,因此我们可以伪造payload表达式。

struct nft_payload {
    enum nft_payload_bases    base:8;
    u8            offset;
    u8            len;
    u8            dreg;
};

image-20240227194109554

regs下方存在着nft_do_chain函数返回地址,因此可以直接通过payload表达式将提权payload注入进来。

image-20240227194544551

由于我们可以伪造payload表达式,因此注入的payload长度不受限,因此采用

  • commit_creds(prepare_kernel_cred(0)),构造root凭证
  • 接着利用find_task_by_vpidinit_nsproxy以及switch_task_namespaces切换命名空间。
  • 最后利用蹦床swapgs_restore_regs_and_retrun_to_usermode返回到用户空间完成提权利用。

image-20240227195613084

完整exphttps://github.com/h0pe-ay/Vulnerability-Reproduction/tree/master/CVE-2023-35001(nftables)

更多网安技能的在线实操练习,请点击这里>>


蚁景网安实验室
53 声望45 粉丝

蚁景网安实验室(www.yijinglab.com)-领先的实操型网络安全在线教育平台 真实环境,在线实操学网络安全 ;内容涵盖:系统安全,软件安全,网络安全,Web安全,移动安全,CTF,取证分析,渗透测试,网安意识教育等。