
ثغرة أمنية متعلقة بلينكس
ما هو هذا المستودع: هو إعادة إنتاج عملية ودراسة من جانبي لـ CVE-2023-32233، وهي ثغرة استخدام بعد التحرير (use-after-free) في نظام nf_tables الفرعي لـ Netfilter في نواة لينكس تسمح بتصعيد الامتيازات محليًا، وقد كُشف عنها علنًا في مايو 2023 بواسطة Patryk Sondej و Piotr Krysiuk.
الإشادة: إن PoC (exploit.c) والكتابة الأصلية من إعداد
@Liuk3r. عملي في هذا المستودع
هو إعادة إنتاج الاستغلال في مختبر خاص بي (Ubuntu 23.04، نواة 6.2.0-20)
وتوثيق السبب الجذري وسلسلة الاستغلال أدناه. وقد أُجريت جميع الاختبارات
على أجهزة مختبر مخصصة.
يعالج nf_tables تحديثات التكوين كدفعة ذرية (atomic batch). غير أن التحقق من صحة كل عملية مقابل تغييرات الحالة للعمليات السابقة في نفس الدفعة غير كافٍ. على وجه التحديد:
nft_rule تحتوي على تعبير lookup على
nft_set مجهول يحمل بعض العناصر.NFT_MSG_DELRULE — تحذف القاعدة، مما يحذف ضمنيًا تعبير
lookup وnft_set المجهول؛NFT_MSG_DELSETELEM — تحذف عنصرًا من المجموعة المجهولة المحذوفة بالفعل.nf_tables_commit_release() الموارد
في nf_tables_destroy_list، وتتم معالجتها لاحقًا بواسطة
nf_tables_trans_destroy_work():
أولًا: nft_commit_release() → nf_tables_rule_destroy() →
nft_lookup_destroy() → nft_set_destroy() → kvfree() تحرر
nft_set؛
ثم، من أجل NFT_MSG_DELSETELEM، تستدعي nf_tables_set_elem_destroy()
الدالة nft_set_elem_ext() التي تفك مرجعية nft_set المحرَّر:
إذا أُفسد set->ops->elemsize، فسيُفسَّر موقع ذاكرة يختاره المهاجم
على أنه nft_set_ext — وهي البدائية التي يُبنى عليها كل شيء آخر.
nf_tables_trans_destroy_work() الذي يعمل في
مؤشر ترابط عامل في الخلفية: أدخل عملية تدمير مجموعة كبيرة كتأخير
متحكم فيه، وأبقِ المعالجات الأخرى مشغولة، وأعد تخصيص الكتلة المحرَّرة
nft_set من نفس المعالج باستخدام nft_set من نوع مختلف
(بـ elemsize مختلف) → ارتباك نوع (type confusion).nft_set_ext فاسدة بإزاحات خارج النطاق بحيث
تجتاز nf_tables_set_elem_destroy() الكتل المجاورة كقائمة من
تعبيرات nft_expr لتدميرها.nft_log بـ NFTA_LOG_PREFIX متحكم فيه؛
تحرر nft_log_destroy() priv->prefix، مما يمنح
بدائية تخصيص متداخل في kmalloc-{8..192} (محدودة بالبايت الصفري أولًا).nft_object->udata لإزالة قيد البايت الصفري
عن القراءة المعلقة.من الجدير بالذكر أن البدائيات المختارة تتجنب أي شيء قد تحجبه CFI — فلا حاجة لاختطاف الاستدعاءات غير المباشرة في أي خطوة.
SLAB_FREELIST_HARDENED)، وINIT_ON_FREE، وقيود إعادة استخدام
البلاطات لكل معالج — جميعها تستهدف الخطوة 1؛ وCFI (حيثما وُجدت) تقيّد الخطوة 3+.nf_tables
التي تحتوي DELRULE+DELSETELEM على مجموعات مجهولة؛ وفرز الأعطال بحثًا عن
nft_set_elem_ext / nf_tables_trans_destroy_work في تتبّع الاستدعاءات.nftables صلاحية CAP_NET_ADMIN، لكن
مساحات أسماء المستخدم غير المميزة تمنحها — ولهذا السبب
يُعد kernel.unprivileged_userns_clone=0 مقبض تقوية ذا معنى.تم الاختبار تحت Ubuntu 23.04 (Lunar Lobster)، النواة 6.2.0-20-generic.
sudo apt install gcc libmnl-dev libnftnl-dev
gcc -Wall -o exploit exploit.c -lmnl -lnftnl
يستهدف ملف التعريف المدمج نوى Ubuntu 23.04 الثنائية
(linux-image-6.2.0-20-generic 6.2.0-20.20). لاختبار نوى أخرى،
استخرج الرموز في ملف profile:
modprobe nf_tables
egrep ' (nft_counter_ops|nft_counter_destroy|free_percpu|modprobe_path)(\s|$)' /proc/kallsyms > profile
يختلف تخطيط كود الآلة للدالة nft_counter_destroy() تبعًا للمترجم
والخيارات؛ راجع ORIGIN.md للمرجع الكامل للمعلمات
(nft_counter_destroy_call_offset/mask/check) ومقابض ضبط السباق
(race_lead_sleep وغيرها). احتمالية النجاح المبلَغ عنها هي ≥80% على
أنظمة Intel عارية (bare-metal) خاملة؛ بعض البنى الدقيقة (مثل Alder Lake)
تحتاج ضبطًا إضافيًا.
يترك PoC النواة في حالة غير مستقرة مع ذاكرة فاسدة بعد تشغيل ناجح. اختبر فقط على نظام مخصص قابل للتخلص منه أو لقطة آلة افتراضية — وليس أبدًا على أي شيء يحتوي على بيانات تهمك.
exploit.c — كود مصدر PoC (بواسطة @Liuk3r)ORIGIN.md — الكتابة الأصلية للثغرة والاستغلال (بواسطة Liuk3r)README.md — هذا الملف: إعادة الإنتاج + ملاحظات تحليليأُجري البحث لأغراض دفاعية/تعليمية في بيئة مختبر معزولة.
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
void *elem)
{
return elem + set->ops->elemsize;
}
nft_dynset لنوعين من التعبيرات ذات الحالة:
nft_counter — يسرّب nft_counter_ops → قاعدة وحدة
nf_tables.ko (يكسر KASLR للوحدة)؛nft_quota — يمنح مؤشر consumed قراءة عشوائية
(NFT_MSG_GETSETELEM → nft_quota_do_dump() → NFTA_QUOTA_CONSUMED)
وكتابة عشوائية (تضيف nft_overquota() قيمة skb->len إلى
*priv->consumed على حركة مرور الحلقة المحلية).modprobe_path ("/sbin/modprobe" → "//tmp/modprobe") →
تنفيذ عملية جذر بمحتوى يتحكم فيه المهاجم.