
PoC
CVE-2022-37706

مرحبًا يا رفاق، هذه المرة سأتحدث عن ثغرة 0-day حديثة اكتشفتها في أحد
مديري النوافذ الرئيسيين للينكس يُدعى Enlightenment (https://www.enlightenment.org/).
هذه الثغرة ستمنح أي مستخدم صلاحيات الجذر بسهولة وفورية.
تم اختبار الاستغلال على Ubuntu 22.04، لكنه سيعمل بشكل جيد على أي توزيعة.
أولًا، Enlightenment هو مدير نوافذ، ومُركِّب، وسطح مكتب بسيط
لينكس (المنصة الأساسية)، وBSD وأي نظام UNIX متوافق آخر.
لقد قمت بتثبيت مدير النوافذ هذا لتجربته قليلًا. كان مثيرًا للاهتمام
بالنسبة لي لأنه يحتوي على الكثير من الأدوات ويبدو أنيقًا جدًا بصراحة.
بعد تثبيت الحزمة باستخدام apt install enlightenment، قمت بفحص
الملفات والأدلة المثبتة على نظامي، وجدت الكثير من الوحدات والكثير من الملفات التنفيذية المساعدة،
لكن الأكثر إثارة للاهتمام هو:
➜ enlightenment cd /usr/lib/x86_64-linux-gnu/enlightenment/
➜ enlightenment find . -perm -4000
./utils/enlightenment_ckpasswd
./utils/enlightenment_system
./utils/enlightenment_sys
إنه يثبّت بعض الملفات التنفيذية SUID، ثم فكرت إذا كان يمكنني استخدام أحدها
لتصعيد الصلاحيات إلى الجذر. كانت جميع الملفات التنفيذية تبدو آمنة ومكتوبة بشكل جيد.
الملف التنفيذي الذي سنتحدث عنه هو enlightenment_sys.
كما هو الحال مع أي هدف آخر، نختار استراتيجية للتطبيق بعد إجراء بعض التقييم المسبق،
راجع مدونتي هنا إذا لم تفعل بعد (https://pwn-maher.blogspot.com/2020/10/vulnerability-assessment.html)
قمت بتدقيق الكود باستخدام نهج من الأعلى إلى الأسفل.
ولأن مدير النوافذ هذا مفتوح المصدر، سيكون الكود المصدري متاحًا
لجميع تلك الملفات التنفيذية والوحدات.
لذا أول شيء فعلته هو apt source enlightenment للحصول على كل الكود المصدري،
ومع القليل من البحث يمكننا الوصول إلى كود الملف التنفيذي المستهدف.
ولكن لتصحيح أخطاء الملف التنفيذي، قمت بتحميله إلى Ghidra للتحليل وللحصول على العناوين
لتحديد نقاط التوقف وغير ذلك.
لم يتم العثور على رموز في المحاولة الأولى، لكن لا حاجة لها إذ اتضح أنه
ملف تنفيذي صغير نسبيًا.
بشكل مفاجئ، وجدت أنه من الممتع جدًا النظر إلى الكود الزائف المُفكك من
Ghidra بدلًا من النظر مباشرة إلى المصدر (تجنب الماكروهات، وتجنب أيضًا تلك الفحوصات
الخاصة بنظام التشغيل المستخدم لتجميع كتلة معينة من الكود).
إذن لنبدأ التحليل.
1- العب مع الملف التنفيذي.
لنشغّل الملف لرؤية بعض المعلومات عن هدفنا:
لقطة شاشة
تشغيل الملف التنفيذي لا يعطي أي مخرجات:
لقطة شاشة
إعطاء الوسيط --help أعطى هذا المخرجات:
لقطة شاشة
آسف، سأستخدمه للحصول على صلاحيات الجذر.
التالي، دعنا نستخدم strace لنرى إذا كان سيستخدم أي استدعاءات نظام مشبوهة مثل
execve أو openat:
strace ./enlightenment_sys 2>&1 | grep open
لقطة شاشة
إنه يفتح فقط مكتبات معروفة في أماكن ليس لدينا صلاحية العبث بها.
strace ./enlightenment_sys 2>&1 | grep exec
لقطة شاشة
2- دعنا نفكك هندسة الملف التنفيذي ثم نستغله.
أنشأت مشروع Ghidra جديدًا، وقمت بتحميل هذا الملف التنفيذي تحديدًا.
بما أنه لم يتم العثور على الرموز، يمكننا تحديد الدالة الرئيسية باستخدام entry.
الوسيط الأول لدالة entry هو main نفسها.
أعدت تسميتها إلى main للرجوع إليها لاحقًا.
بالتمرير لأسفل قليلًا يمكنني بالفعل رؤية دالة system() وهي تُستخدم.
كهاوٍ في استغلال الثغرات، أمضي أيامًا في التحديات لاستدعاء هذه الدالة تحديدًا x)
قمت بعكس هندسة الملف التنفيذي بحثًا عن ثغرة تلف في الذاكرة أو مشاكل في الكومة
، لكن في الواقع كان حقن أوامر غريبًا.
الملف التنفيذي يتخذ كل الاحتياطات الأمنية قبل تشغيل system، لكن للأسف
يمكننا دائمًا حقن مدخلاتنا هناك.
لقطة شاشة
حسنًا، الآن دعنا نتنقل في الملف التنفيذي من الأعلى حتى دالة system الخاصة بنا، محاولين
حقن مدخلاتنا هناك.
أولًا، يتحقق الملف التنفيذي فقط إذا كان الوسيط الأول هو --help أو -h ويعرض تلك
الرسالة التي رأيناها سابقًا.
لقطة شاشة
ثانيًا، يرفع صلاحياته إلى الجذر.
لقطة شاشة
بعد ذلك، يقوم بإلغاء تعيين جميع متغيرات البيئة تقريبًا (احتياطات أمنية) لعدم
استدعاء ملف تنفيذي آخر غير مقصود.
لقطة شاشة
إذن إذا كان الوسيط الأول الذي أدخلناه هو "mount"، فسيدخل إلى هذا الفرع، ويتحقق من بعض
الخيارات المُعطاة، وسيتم تعيين تلك الخيارات على المكدس.
بعد ذلك يتحقق إذا كانت المعلمة التالية بعد mount هي UUID=، لا نريد الدخول
إلى هنا، لذا أعطينا "/dev/../tmp/;/tmp/exploit".
لقطة شاشة
بهذه الطريقة نجتاز الفحص في السطر 410، فحص strncmp.
لأنه إذا لم يبدأ بـ /dev/ فسيخرج الملف التنفيذي.
بعد ذلك هناك استدعاء لدالة stat64 على ذلك الملف الذي قدمناه، لاحظ أنه يمكننا
إنشاء مجلد باسم ";" وهذا سيسبب حقن الأوامر.
حتى الآن، أنشأ الاستغلال هذا الملف /dev/../tmp/;/tmp/exploit،
لكن هذا ليس الاستغلال الذي سيتم استدعاؤه.
لقطة شاشة
لقطة شاشة
نقترب الآن من system().
الآن p (المؤشر) يتم تحديثه ليصبح آخر وسيط مُعطى للملف التنفيذي SUID الخاص بنا،
/tmp///net.
لماذا نقدم /tmp///net بينما يمكننا تمرير /tmp/net؟
سنتجاوز هذا الفحص:
if (((next_next == (char *)0x0) || (next_next[1] == '\0')) || ((long)next_next - (long)p != 6))
نحن نحتاج إلى وجود /tmp/net وأن يكون /tmp/// بطول 6.
الآن ستتحقق آخر استدعاء stat64 من وجود "/dev/net"
__snprintf_chk(cmd,0x1000,1,0x1000,"/dev%s",next_next);
وسيجده، لذلك نجتاز ذلك الفحص الأخير.
الآن سيتحقق من توفر بعض الملفات، لكن هذا ليس مهمًا
في هذه المرحلة، لأننا جاهزون وقريبون جدًا من تفعيل تنفيذ أوامر عشوائي.
الآن eina_strbuf_new() سيعمل فقط على تهيئة الأمر الذي سيتم تمريره إلى
system، المشكلة هنا أننا أدخلناه على الشكل:
/bin/mount -o noexec,nosuid,utf8,nodev,iocharset=utf8,utf8=0,utf8=1,uid=$(id -u), "/dev/../tmp/;/tmp/exploit" /tmp///net
لكن الملف التنفيذي يستدعي eina_strbuf_append_printf() عدة مرات ويصبح الأمر:
/bin/mount -o noexec,nosuid,utf8,nodev,iocharset=utf8,utf8=0,utf8=1,uid=$(id -u), /dev/../tmp/;/tmp/exploit /tmp///net
لاحظ أن علامات الاقتباس المزدوجة قد أُزيلت، وسنكون قادرين على استدعاء /tmp/exploit
بصلاحيات الجذر.
لقطة شاشة
لقد بذل الملف التنفيذي قصارى جهده للتخفيف من أي سلوك غير مقصود، لكن كالعادة
أي شيء يمكن اختراقه. لم أكن أتوقع استغلال هذا باستخدام ثغرة منطقية
مثل هذه.
أتمنى أن تكون الثغرة التالية CVE عبارة عن تلف في الذاكرة يؤدي إلى LPE إلى الجذر.