
يحتوي هذا المستودع على منشور مدونة حول تحليلي لـ CVE-2018-19987، وهو هجوم حقن أوامر نظام تشغيل مصادق عليه يؤثر على العديد من أجهزة توجيه D-Link
مرحبًا!
في هذا المقال القصير، سأشرح تحليلاً سريعًا قمت به لفهم التفاصيل وراء CVE-2018-19987 بشكل أفضل. في البداية، بحثت عن هذه الثغرة لأنني اعتقدت أنه لا توجد معلومات عامة أو استغلال. بعد وقت قصير من إجراء التحليل الأول، وجدت اثنين من PoCs العامة على GitHub يمكنك العثور عليها هنا و هنا.
نظرًا لأنني كنت قد أنجزت معظم العمل ولم أجد تحليلاً كاملاً، قررت كتابة المقال على أي حال.
أتمنى أن تستمتع به!
تحديث: حسنًا .. بعد البحث أثناء توقفي في هذا المقال، وجدت المقال التالي الذي يصف ثغرة مشابهة جدًا (CVE-2018-19986) في جهاز D-Link DIR-818. سلسلة تحليل ثغرات أجهزة التوجيه (5): تحليل وإعادة إنتاج ثغرة حقن الأوامر CVE-2018-19986 في DIR-818LW&828 (مترجم بواسطة Google) بقلم Ogur1.
بدأت تحليلي بجمع كل المعلومات التي استطعت عن الجهاز:
ملاحظة: أجريت كل التحليل مع إصدار البرنامج الثابت v3.01B02.
المعلومات العامة لهذه الثغرة، المتاحة على صفحة Mitre، وفرت معلومات كافية للبدء: أجهزة D-Link DIR-822 Rev.B 202KRb06, DIR-822 Rev.C 3.10B06, DIR-860L Rev.B 2.03.B03, DIR-868L Rev.B 2.05B02, DIR-880L Rev.A 1.20B01_01_i3se_BETA, وDIR-890L Rev.A 1.21B02_BETA تعالج IsAccessPoint بشكل خاطئ في /HNAP1/SetAccessPointMode. في كود مصدر SetAccessPointMode.php، يتم حفظ معامل IsAccessPoint في ملف البرنامج النصي ShellPath دون أي فحص regex. بعد تنفيذ ملف البرنامج النصي، يحدث حقن الأوامر. يمكن أن تحتوي رسالة XML الضعيفة /HNAP1/SetAccessPointMode على أحرف خاصة في عنصر IsAccessPoint مثل سلسلة telnetd.
لبدء التحليل، كنت بحاجة إلى شيء لأنظر إليه، لذلك شرعت في استخراج نظام الملفات الخاص بجهاز التوجيه.
binwalk -eM DIR822C1_FW301WWb02.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380 0x288C LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 4213444 bytes
1376372 0x150074 PackImg section delimiter tag, little endian size: 10505216 bytes; big endian size: 5021696 bytes
1376404 0x150094 Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 5019773 bytes, 2282 inodes, blocksize: 131072 bytes, created: 2016-03-18 09:35:31
كما نرى، يكتشف Binwalk نظام ملفات لينكس. إذا ألقينا نظرة أعمق على المعلومات المتاحة، نرى أن الإشعار يذكر مسار /HNAP1. لذا، يمكننا البدء في النظر في كيفية معالجة جهاز التوجيه لهذه الروابط.
كما هو موضح في منشور المدونة الممتاز /dev/tty0، تتم معالجة هذه الروابط في النهاية بواسطة ثنائي يسمى cgibin، الموجود في htdocs/cgibin. لكنني أردت فهمًا أفضل لكيفية تكوين ذلك، وفي النهاية قادني ذلك إلى فهم كيفية تكوين خادم HTTP لمعالجة الطلبات. شرعت في البحث عن اسم ملف httpd.conf، بافتراض أنه يُستخدم لتكوين خادم HTTP، ووجدت ملفًا يسمى HTTP.php تحت مجلد /etc/services/، يحتوي من بين أشياء أخرى على الأسطر التالية المثيرة للاهتمام:
$httpd_conf = "/var/run/httpd.conf";
fwrite("a",$START, "xmldbc -P /etc/services/HTTP/httpcfg.php > ".$httpd_conf."\n");
fwrite("a",$START, "event PREFWUPDATE add /etc/scripts/prefwupdate.sh\n");
fwrite("a",$START, "httpd -f ".$httpd_conf."\n");
fwrite("a",$START, "event HTTP.UP\n");
fwrite("a",$START, "exit 0\n");
افترضت أنه في مرحلة ما يتم تنفيذ هذا الملف ويكتب ملف /var/run/httpd.conf. لمعرفة كيفية تكوين خادم الويب، شرعت في تحليل ملف /etc/services/HTTP/httpcfg.php (أدرجت فقط الأجزاء ذات الصلة):
if ($hnap > 0)
{
echo
" Control". "\n".
" {". "\n".
" Alias /HNAP1". "\n".
" Location /htdocs/HNAP1". "\n".
" External". "\n".
" {". "\n".
" /usr/sbin/hnap { hnap }". "\n".
" }". "\n".
" IndexNames { index.hnap }". "\n".
" }". "\n";
}
الآن لدينا كل القطع! يمكننا افتراض أن خادم الويب مهيأ لمعالجة طلبات HTTP إلى /HNAP1 باستخدام /usr/sbin/hnap، وبناءً على منشور مدونة /dev/tty0 نعلم أنه سيكون رابطًا للثنائي htdocs/cgibin.
الخطوة التالية كانت إلقاء نظرة على الثنائي cgibin لفهم كيفية معالجته لطلبات HNAP. في الصورة التالية يمكننا رؤية جزء من دالة main المفككة حيث تتم مقارنة مسار URL الذي تم تمريره مع مسارات مختلفة (مثل session.cgi, authentication.cgi, captcha.cgi، على سبيل المثال لا الحصر) حتى يتم العثور على hnap ويتم استدعاء دالتنا hnap_main.
ملاحظة: أثناء تحليل الدالة main، واجهت بعض المشكلات في تحديد سلسلة hnap لأن Ghidra لم يكتشفها كسلسلة أثناء التحليل الأولي.
الخطوة التالية كانت فهم ما تفعله هذه الدالة. سأقدم فقط مقتطفات من الكود للأجزاء ذات الصلة التي ستساعد في فهم ما تفعله الدالة بشكل أفضل، وسأكمل أجزاء أخرى ذات صلة ببعض الكود الوهمي —أعدت تسمية بعض المتغيرات لتوضيح الغرض منها.
...
HTTP_SOAPACTION = getenv("HTTP_SOAPACTION");
REQUEST_METHOD = getenv("REQUEST_METHOD");
HNAP_AUTH = getenv("HTTP_HNAP_AUTH");
__haystack = getenv("HTTP_COOKIE");
pcVar1 = getenv("HTTP_REFERER");
...
if (HTTP_SOAPACTION != "") {
if (HTTP_SOAPACTION == GetDeviceSettings) {
...
} else {
// These actions will occur during auth. Process
if ("GetCAPTCHAsetting" in HTTP_SOAPACTION) {
sess_generate_captcha();
} else {
if ("Login" in HTTP_SOAPACTION) {
perform_login();
}
// We'll land here once auth.
if (HNAP_AUTH != "") {
if ("uid=" in HTTP_COOKIE){
is_valid_auth = perform_auth_process()
if (is_valid_auth) {
if("logout" in HTTP_SOAPACTION){
perform_logout();
// If we are auth. and NOT trying to logout
// the code will try to perform the action
// we requested
} else {
// If we arrive here we win
// interesting code below
goto LAB_004141d4;
}
}
}
}
// If we are not authenticated we can't do anything
Return "You need proper authorization to use this resource"
}
}
} else {
...
}
LAB_004141d4:
hnap_action = get_hnap_operation(HTTP_SOAPACTION);
if (HTTP_SOAPACTION != "") {
hnap_action_len = strlen(hnap_action);
}
snprintf(path_to_hnap_php_file,0x100,"%s/%s.php","/etc/templates/hnap/",hnap_action);
if (!check_file_access(path_to_hnap_php_file)){
return "HNAP ACTION DOES NOT EXIST (FAIL)"
}
if (REQUEST_METHOD == "POST") {
// Here arguments for the PHP are extracted
parse_request_and_extract_xml()
if (hnap_action == "GetFirmwareStatus") {
system("sh /etc/events/checkfw.sh > /dev/console");
}