
مختبر قائم على Docker يوضح ثغرة تحليل URI في Nginx CVE-2013-4547 مع استغلال خطوة بخطوة لتجاوز الصلاحيات وتنفيذ الأكواد.
النسخ المتأثرة: Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7
الروابط المرجعية:
هذه الثغرة لا ترتبط في الواقع كثيرًا بتنفيذ الأكواد، فسببها الرئيسي هو التحليل الخاطئ لـ URI الخاص بالطلب، والحصول الخاطئ على اسم الملف الذي يطلبه المستخدم، مما يؤدي إلى تجاوز الصلاحيات وتأثيرات تنفيذ الأكواد اللاحقة.
على سبيل المثال، عندما يطابق Nginx طلبًا ينتهي بـ .php، فإنه يرسله إلى fastcgi للتحليل، والصياغة الشائعة تكون كالتالي:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /var/www/html;
}
في الوضع الطبيعي (عند إيقاف pathinfo)، يتم إرسال الملفات ذات الامتداد .php فقط إلى fastcgi للتحليل.
في حالة وجود CVE-2013-4547، عندما نطلب 1.gif[0x20][0x00].php، فإن هذا URI يطابق التعبير المعتاد \.php$، ويمكن أن يدخل إلى كتلة Location هذه؛ ولكن بعد الدخول، يعتقد Nginx خطأً أن الملف المطلوب هو 1.gif[0x20]، ويقوم بتعيينه كقيمة SCRIPT_FILENAME ويرسله إلى fastcgi.
يقوم fastcgi بتحليل القيمة SCRIPT_FILENAME مما يؤدي في النهاية إلى ثغرة تحليل.
لذا، كل ما نحتاجه هو رفع ملف ينتهي بمسافة، وسيقوم PHP بتحليله.
مثال آخر، العديد من المواقع تقيد عناوين IP المسموح لها بالوصول إلى لوحة الإدارة:
location /admin/ {
allow 127.0.0.1;
deny all;
}
يمكننا طلب URI التالي: /test[0x20]/../admin/index.php، هذا URI لا يطابق /admin/ الموجود بعد location، وبالتالي يتجاوز التحقق من IP؛ لكن الملف المطلوب في النهاية هو /test[0x20]/../admin/index.php، أي /admin/index.php، وهكذا ننجح في الوصول إلى لوحة الإدارة. (الشرط هو وجود دليل باسم test : هذه إحدى خصائص نظام Linux، فإذا كان الدليل غير موجود، حتى بعد القفز إلى المستوى الأعلى، سيظهر خطأ عدم وجود الملف، ولا يوجد هذا القيد في Windows)
تشغيل بيئة الثغرة:
docker-compose build
docker-compose up -d
بعد تشغيل البيئة، قم بزيارة http://your-ip:8080/ لتظهر صفحة رفع ملفات.
هذه البيئة تستخدم التحقق بالقائمة السوداء، لا يمكننا رفع ملفات بامتداد php، لذا نحتاج لاستغلال CVE-2013-4547. نقوم برفع ملف باسم 1.gif ، لاحظ المسافة في النهاية:

قم بزيارة http://your-ip:8080/uploadfiles/1.gif[0x20][0x00].php، ستجد أن PHP قد تم تحليله:

ملاحظة: [0x20] يمثل مسافة، و[0x00] يمثل \0، وهذان الحرفان لا يحتاجان إلى تشفير.