前言
本文將介紹如何繞過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; };
具體的佈局如下
可以看到data_from
與data_to
都是從用戶態中傳遞過去的數據,因此我們可以在這些區域內僞造表達式,這有點像在CTF
中,我們泄露了堆塊基址後,隨意僞造堆塊。
由於我們有0x28
字節的空間,但是實際能夠操作的空間是data_from
與data_to
兩段,即0x20
的空間大小。因此我們需要挑選小於0x20
的規則表達式進行僞造,並且能夠執行泄露功能的。
這裏作者選用了byteorder
表達式,可以看到該表達式在對齊後只佔用八字節。
struct nft_byteorder { u8 sreg; u8 dreg; enum nft_byteorder_ops op:8; u8 len; u8 size; };
構造後,可以發現還有八字節的data_to
沒有用,但是並不能直接丟棄不適用,因爲在調用完byteorder
操作後還需要繼續執行其他規則表達式。
但是其他表達式都是需要大於0x8
的,畢竟一個操作指針就佔用八字節了,此時作者選用了meta
表達式。可以看到meta
表達式也只用到了三個字節,剛好對應range
表達式的sreg
、len
以及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 = ®s->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
表達式。由於我們直接僞造了規則表達式,因此不會進行寄存器參數的校驗,只要選擇內核地址選擇泄露即可。
這裏簡單說一下僞造的規則頭,此時的len
需要設置爲0x20以及islast
需要設置爲0。
最後泄露的效果如下,即使內核已經拋出了異常,但是不會影響後續表達式的正常執行。
【---- 幫助網安學習,以下所有學習資料免費領!領取資料加 we~@x: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; };
在regs
下方存在着nft_do_chain
函數返回地址,因此可以直接通過payload
表達式將提權payload
注入進來。
由於我們可以僞造payload
表達式,因此注入的payload
長度不受限,因此採用
-
commit_creds(prepare_kernel_cred(0))
,構造root
憑證 -
接着利用
find_task_by_vpid
、init_nsproxy
以及switch_task_namespaces
切換命名空間。 -
最後利用蹦牀
swapgs_restore_regs_and_retrun_to_usermode
返回到用戶空間完成提權利用。
完整exp
:https://github.com/h0pe-ay/Vulnerability-Reproduction/tree/master/CVE-2023-35001(nftables)