
استغلال تصعيد الامتيازات على Linux عبر snapd (CVE-2019-7304)
في يناير 2019، تم اكتشاف أن الإصدارات الحالية من Ubuntu Linux معرضة لتصعيد الصلاحيات محليًا بسبب خلل في واجهة برمجة تطبيقات snapd. يحتوي هذا المستودع على برهان المفهوم (POC) الأصلي للاستغلال، وهو متاح لأغراض البحث والتعليم. للحصول على شرح تفصيلي للثغرة والاستغلال، يرجى الرجوع إلى التدوينة هنا.
يأتي Ubuntu مع snapd افتراضيًا، لكن أي توزيعة يجب أن تكون قابلة للاستغلال إذا كانت هذه الحزمة مثبتة لديها. يمكنك بسهولة التحقق مما إذا كان نظامك معرضًا للخطر. نفّذ الأمر أدناه. إذا كان إصدار snapd لديك هو 2.37.1 أو أحدث، فأنت آمن.
$ snap version
...
snapd 2.37.1
...
لاحظ أن بعض الأنظمة تُرجع إصدار حزمة التوزيعة من snapd عند تشغيل هذا الأمر، على عكس الإصدار الرئيسي (upstream) الموضح في المثال أعلاه. إذا كان إصدار snapd لديك يتضمن إشارة إلى شيء مثل رقم إصدار Ubuntu ملحقًا به (مثال: 2.34.2ubuntu0.1 أو 2.35.5+18.10.1) فيرجى الاطلاع على هذا الرابط لتحديد ما إذا كنت تشغّل إصدارًا مصححًا.
يتجاوز هذا الاستغلال فحوصات التحكم في الوصول لاستخدام دالة API مقيدة (POST /v2/create-user) لخدمة snapd المحلية. يستعلم هذا من Ubuntu SSO عن اسم مستخدم ومفتاح SSH عام لعنوان بريد إلكتروني معين، ثم ينشئ مستخدمًا محليًا بناءً على هذه القيم.
يتطلب الاستغلال الناجح لهذا الإصدار اتصالًا صادرًا بالإنترنت وخدمة SSH يمكن الوصول إليها عبر localhost.
للاستغلال، أنشئ أولًا حسابًا على Ubuntu SSO. بعد تأكيده، عدّل ملفك الشخصي وارفَع مفتاح SSH عامًا. ثم شغّل الاستغلال على هذا النحو (مع استخدام مفتاح SSH الخاص المقابل للمفتاح العام الذي رفعته):
python3 ./dirty_sockv1.py -u "[email protected]" -k "id_rsa"
[+] Slipped dirty sock on random socket file: /tmp/ktgolhtvdk;uid=0;
[+] Binding to socket file...
[+] Connecting to snapd API...
[+] Sending payload...
[+] Success! Enjoy your new account with sudo rights!
[Script will automatically ssh to localhost with the SSH key here]
يتجاوز هذا الاستغلال فحوصات التحكم في الوصول لاستخدام دالة API مقيدة (POST /v2/snaps) لخدمة snapd المحلية. وهذا يسمح بتثبيت أي snaps. تتجاوز snaps في وضع "devmode" بيئة العزل (sandbox) وقد تتضمن "خطاف تثبيت" (install hook) يتم تشغيله في سياق root وقت التثبيت.
يستغل dirty_sockv2 الثغرة لتثبيت snap فارغ بوضع "devmode" يتضمن خطافًا يضيف مستخدمًا جديدًا إلى النظام المحلي. سيمتلك هذا المستخدم صلاحيات لتنفيذ أوامر sudo.
على عكس الإصدار الأول، لا يتطلب هذا تشغيل خدمة SSH. كما أنه يعمل على الإصدارات الأحدث من Ubuntu دون أي اتصال بالإنترنت إطلاقًا، مما يجعله مقاومًا للتغييرات وفعّالًا في البيئات المقيدة.
ملاحظة للتوضيح: لا يختبئ هذا الإصدار من الاستغلال داخل snap ضار. بدلًا من ذلك، يستخدم snap ضارًا كآلية توصيل للحمولة (payload) الخاصة بإنشاء المستخدم. هذا ممكن بفضل نفس خلل uid=0 الموجود في الإصدار 1
يجب أن يكون هذا الاستغلال فعّالًا أيضًا على الأنظمة غير المبنية على Ubuntu التي ثبّتت snapd ولكنها لا تدعم واجهة برمجة تطبيقات "create-user" بسبب عدم توافق صيغة أوامر Linux shell.
قد لا تتوفر لدى بعض أنظمة Ubuntu الأقدم (مثل 16.04) مكونات snapd المطلوبة للتثبيت الجانبي (sideloading). إذا كان الأمر كذلك، فقد يدفع هذا الإصدار من الاستغلال إلى تثبيت هذه التبعيات. أثناء ذلك التثبيت، قد يرقّي snapd نفسه إلى إصدار غير معرض للخطر. تظهر الاختبارات أن الاستغلال لا يزال ناجحًا في هذا السيناريو. راجع قسم استكشاف الأخطاء وإصلاحها لمزيد من التفاصيل.
للاستغلال، ما عليك سوى تشغيل السكربت دون وسائط على نظام معرض للخطر.
python3 ./dirty_sockv2.py
[+] Slipped dirty sock on random socket file: /tmp/gytwczalgx;uid=0;
[+] Binding to socket file...
[+] Connecting to snapd API...
[+] Deleting trojan snap (and sleeping 5 seconds)...
[+] Installing the trojan snap (and sleeping 8 seconds)...
[+] Deleting trojan snap (and sleeping 5 seconds)...
********************
Success! You can now `su` to the following account and use sudo:
username: dirty_sock
password: dirty_sock
********************
إذا كنت تستخدم الإصدار الثاني، واكتمل الاستغلال لكنك لا ترى حسابك الجديد، فقد يكون السبب بعض تحديثات snap في الخلفية. يمكنك عرض هذه التحديثات بتنفيذ snap changes ثم snap change #، مع الإشارة إلى السطر الذي يعرض تثبيت snap الخاص بـ dirty_sock. في النهاية، يجب أن تكتمل هذه التحديثات ويصبح حسابك قابلاً للاستخدام.
يبدو أن الإصدار 1 هو الأسهل والأسرع، إذا كانت بيئتك تدعمه (خدمة SSH قيد التشغيل ويمكن الوصول إليها من localhost).
ستُخرج الأنظمة غير المعرضة للخطر شيئًا مثل التالي:
[!] System may not be vulnerable, here is the API reply:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Date: Mon, 18 Feb 2019 07:07:12 GMT
Content-Length: 119
{"type":"error","status-code":401,"status":"Unauthorized",
"result":{"message":"access denied","kind":"login-required"}}
يرجى فتح issues لأي شيء غريب.
تم الإبلاغ عن المشكلة مباشرة إلى فريق snapd عبر متتبع الأخطاء الخاص بـ Ubuntu. يمكنك قراءة السلسلة الكاملة هنا.
أعجبتني كثيرًا استجابة Canonical لهذه المشكلة. كان الفريق رائعًا في التعامل معه، وبشكل عام فإن التجربة تجعلني أشعر بارتياح كبير لكوني مستخدمًا لنظام Ubuntu بنفسي.
روابط النشرات العامة:
ملاحظة: أنشر المعلومات فقط في مستودع GitHub هذا، ومدونتي على initblog.com، ومدونة فريقي على shenaniganslabs.io. أي موقع ينتحل صفة مصدر رسمي هو للأسف خارج نطاق سيطرتي.