
أداة استغلال موثوقة + شرح لرفع الامتيازات إلى الجذر. (تم اختبارها على Ubuntu 22.04)
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 جديد، وقمت بتحميل هذا الملف الثنائي المحدد.
نظرًا لعدم العثور على الرموز، يمكننا تحديد الدالة main باستخدام entry.
الوسيط الأول لدالة entry هو main نفسه.
أعدت تسميته إلى main للمراجع المستقبلية.
بالتمرير قليلاً إلى الأسفل، أستطيع بالفعل رؤية الدالة system() وهي تُستخدم.
كمُختبر ثغرات، أقضي أيامًا في التحديات لاستدعاء هذه الدالة المحددة x)
قمت بعكس الملف الثنائي بحثًا عن خطأ في تلف الذاكرة أو بعض مشاكل heap، لكنه في الواقع كان حقن أوامر غريبًا.
يتخذ الملف الثنائي جميع الاحتياطات الأمنية قبل تشغيل 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 جذر.
الإفصاح عبر تويتر: https://twitter.com/maherazz2/status/1569665311707734023