
استغلال نواة لـ CVE-2016-6187 (تصعيد الصلاحيات محليًا)
استغلال نواة لـ CVE-2016-6187 (تصعيد صلاحيات محلي) (الإصدارات المتأثرة: < 4.6.5)
تم تطوير الاستغلال ضد نواة 4.6 مُجمَّعة مخصصة + buildroot (kconfig قريبًا)
ويتغلب على KASLR وSMEP وSMAP (KPTI غير متاح للإصدار 4.6)
الثغرة المستغلّة هي تجاوز سعة بصفر واحد (nullbyte) في كومة الذاكرة (heap) داخل إحدى خطافات LSM الخاصة بـ AppArmor (setprocattr). انظر https://nvd.nist.gov/vuln/detail/CVE-2016-6187
تشير القياسات الأولية إلى احتمال 94.44% لتشغيل صدفة بصلاحيات الجذر. في حالة واحدة من كل 18 حالة، سيُحدث الاستغلال خطأً (oops) في النواة. هناك حاجة إلى مزيد من العمل لتثبيت النواة بالكامل بعد الحصول على صلاحيات الجذر.
نستغل تجاوز البايت الصفري لإفساد البايت الأقل أهمية (LSB) من مؤشر قائمة حرة في kmalloc-128، مما يجعله
يشير فعليًا إلى كائن مُخصَّص بالفعل. بعد ذلك، نقوم بتحرير ذلك الكائن المُخصَّص، مما يسبب سيناريو تحرير مزدوج (double free).
يمكننا الآن تخصيص بنيتين متداخلتين من ذاكرة kmalloc-128. البنية الأولى هي كائن
يمكن قراءة محتواه من مساحة المستخدم. ولهذا اخترت ip6_sf_socklist. البنية الثانية،
التي ستُخصَّص فوق ip6_sf_socklist، يجب أن تحتوي على مؤشرات نواة - rfkill_data خيار مناسب.
يحتوي على مؤشر كومة (قائمة rfkill_data.events فارغة) ومؤشر بيانات عام إلى rfkill_fds (rfkill_data.list.prev).
بمجرد تخصيص rfkill_data فوق ip6_sf_socklist، يمكننا استرجاع مؤشرات النواة عن طريق استدعاء
getsockopt(sock, IPPROTO_IPV6, MCAST_MSFILTER, gsf, &optlen). يمكن بعد ذلك اشتقاق عنوان قاعدة النواة من rfkill_fds.
ثم نسبب سيناريو تحرير مزدوج ثانٍ، لكن هذه المرة نستغل عملية ربط قائمة انتظار الرسائل لاستبدال مؤشر القائمة الحرة
وخداع المُخصِّص ليعيد لنا كتلة من kmalloc-96 بينما نطلب فعليًا كتلة من kmalloc-128.
يمكننا بعد ذلك استغلال عدم تطابق الحجم لتجاوز سعة باتجاه مؤشر القائمة الحرة لكتلة kmalloc-96، مما يمنحنا القدرة على
تخصيص عناوين اعتباطية. في حالتنا، نستهدف بنية ptmx_fops ونستبدل استدعاء
ptmx_fops.unlocked_ioctl بمؤشر إلى أداة تحويل المكدس (stack pivot) الخاصة بنا.
استدعاء ioctl على /dev/ptmx يُفعّل أداة التحويل، فننقل المكدس إلى مكدس مزيف في kmalloc-128 حيث
أعددنا بالفعل سلسلة ROP للمرحلة الأولى.
نظرًا لأن المساحة محدودة على المكدس المزيف في kmalloc-128 (لا نعرف ما إذا كانت الكتلة التالية ستكون على نفس slab)، فإن مهمة
سلسلة ROP للمرحلة الأولى هي نسخ سلسلة ROP للمرحلة الثانية من مساحة المستخدم إلى مخزن سجل dmesg للنواة (__log_buf)
ونقل المكدس إلى __log_buf.
تقوم سلسلة ROP للمرحلة الثانية بعد ذلك بمحاولة إصلاح النواة (استعادة ptmx_fops، ...) قبل استدعاء commit_creds(prepare_kernel_cred(NULL))
لتصعيد الصلاحيات.
وأخيرًا، تخرج من مساحة النواة عبر iretq ونعود، بصلاحيات مرتفعة، إلى الروتين الفرعي execve("/bin/sh", 0, 0) الخاص بنا.
يجب أن يتمكن المستخدمون غير المميزين على الأقل من فتح /dev/rfkill. قد لا تسمح بذلك بعض التوزيعات.
لقد تحققت من Ubuntu وFedora، وكلاهما يسمح للمستخدمين غير المميزين بفتح /dev/rfkill
(على الرغم من أن Fedora يستخدم SELinux بدلاً من AppArmor)
يشرح القسم التالي كيفية إعادة إنتاج تصعيد الصلاحيات المحلي في qemu-x86_64.
أولاً، ستحتاج إلى الحصول على ملف initrd ونواة bzImage. هناك طريقتان:
أسهل وأسرع طريقة. يمكنك العثور على جميع المكونات المطلوبة في prebuilt/.
أو بدلاً من ذلك، يمكنك أيضًا بناء المكونات بنفسك. ببساطة قم بجلب
نواة 4.6 واستخدم
ملف x86_64_vuln_kern_defconfig المرفق في config/ لتجميع bzImage.
بالنسبة لـ initrd، يمكنك على سبيل المثال استخدام buildroot. فقط تأكد
من تعيين الصلاحيات الصحيحة لـ /dev/rfkill في ملف init الخاص بك
chmod 664 /dev/rfkill
هذا هو نفس الإعداد كما في Ubuntu-16.04 والعديد من التوزيعات الأخرى. أيضًا لا تنسَ تجميع
الاستغلال ووضعه في initrd الخاص بك
make
بمجرد حصولك على المكونات، قم بتشغيل الجهاز المُصاب
./boot.sh <path/to/bzImage> <path/to/rootfs.cpio>
ونفّذ الاستغلال
./exploit
قد تحتاج إلى تشغيل الاستغلال عدة مرات، اعتمادًا على ما إذا كنا قد صفّرنا بايت LSB كان صفرًا بالفعل. لاحظ أيضًا أنه لا تزال هناك فرصة بسيطة (ربما 10%-20%؟) للانهيار بعد الحصول على صلاحيات الجذر - وأنا أعمل على ذلك.
استمتع.
ptmx_fops لزيادة الاستقرارkmalloc-128 الحرة لزيادة الاستقرار