سلاسل مرشحات PHP: تحويل تضمين الملف المحلي إلى تنفيذ شيفرة عن بُعد
غالبًا ما يُعامل تضمين الملف المحلي (LFI) كخلل قراءة فقط. يستطيع المهاجم قراءة /etc/passwd أو ربما الشيفرة المصدرية، وتنتهي القصة. غيّرت سلاسل مرشحات PHP هذه الحسبة. فبإساءة استخدام php://filter مع تسلسل مُعدّ بعناية من تحويلات convert.iconv، يمكن للمهاجم توليف بايتات عشوائية داخل تدفق — بما فيها حمولة PHP صالحة — دون رفع ملف أو الكتابة على القرص. ومع نقطة تضمين، تكون النتيجة تنفيذ شيفرة عن بُعد.
1. نقطة التضمين
يمرّر النمط المصاب الكلاسيكي معامل طلب مباشرة إلى include أو require:
<?php
// vulnerable.php
$page = $_GET['page'] ?? 'home';
include(__DIR__ . '/pages/' . $page . '.php');
من يتحكم في page يستطيع الصعود في الأدلة (../../etc/passwd) أو، إذا كانت أغلفة URL مفعّلة، تقديم غلاف مثل php://filter. تُضاف اللاحقة .php، لكن الأغلفة وتقنين المسار قد ينتجان سلوكًا مفيدًا حسب الشيفرة. وأوضح عرض يستخدم تضمينًا بلا لاحقة:
<?php
include($_GET['file']);
2. ماذا يفعل php://filter
يطبّق php://filter مرشحات تدفق على مورد. مثال بسيط يقرأ ملفًا ويفك ترميز base64:
php://filter/convert.base64-decode/resource=/var/www/html/config.php
يمكن تسلسل المرشحات. وكل مرشح يحوّل التدفق قبل أن يستقبله التالي. وتحوّل مرشحات convert.iconv.* بين ترميزات الأحرف، وبعض الترميزات تملك تسلسلات هروب ذات حالة تنتج بايتات محددة. وبتسلسلها وجد الباحثون إمكانية إضافة بيانات مضبوطة إلى بداية التدفق.
3. تقنية Synacktiv
نشرت Synacktiv مولّدًا يبني سلسلة مرشحات تنتج بادئة عشوائية. تبدأ السلسلة بحمولة مرمّزة بـ base64 وتستخدم تسلسل تحويلات iconv لإصدار البايتات المطلوبة في بداية التدفق. ويبدو العنوان المولّد هكذا (مقتطعًا):
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...|convert.base64-decode/resource=php://temp
يؤتمت المولّد البحث عن سلسلة تنتج الحمولة الدقيقة. وفي المختبر:
# تثبيت المولّد في مختبر معزول
git clone https://github.com/synacktiv/php_filter_chain_generator
python3 php_filter_chain_generator/php_filter_chain_generator.py \
--chain '<?php system($_GET["c"]); ?>'
يطبع الأداة عنوان php://filter/.... وتمريره إلى include المصاب يجعل PHP يترجم الحمولة المولّفة وينفّذها. ولا تلمس الحمولة القرص أبدًا، فتتجاوز قيود الرفع وفحوص الامتداد وكثيرًا من مراقبات السلامة.
استخدم هذه التقنية فقط في تقييمات مصرّح بها ومختبرات معزولة. المولّد والخلل الأساسي قويان؛ وتشغيلهما ضد أنظمة لا تملكها غير قانوني.
4. CVE-2024-2961 وعلاقتها بـ glibc
في 2024 نشرت Ambionics بحثًا عن ثغرة iconv في glibc مسماة CVE-2024-2961. وهي كتابة خارج الحدود في معالجة مجموعة أحرف ISO-2022-CN-EXT، تصيب glibc قبل 2.40. ويمكن تفعيلها عبر مرشحات iconv في PHP، وفي الظروف المناسبة تُستخدم لإفساد الذاكرة وتنفيذ شيفرة.
أهميتها لـ LFI أن تقنية سلاسل المرشحات لا تحتاج دائمًا بدائية نظيفة «لتوليف وسم PHP». فخلل فساد ذاكرة في مكتبة التحويل يوفّر مسارًا آخر من بدائية قراءة إلى تنفيذ. ويعتمد الاستغلال الدقيق على إصدار PHP وبناء glibc وحالة الموزّع، ولهذا كان البحث ملحوظًا: فقد حوّل فئة من أخطاء «القراءة فقط» إلى سلسلة RCE موثوقة على توزيعات كثيرة.
صدر PHP 8.5 في 20 نوفمبر 2025. وعلى المؤسسات التحقق من إصداري PHP وglibc معًا؛ فقد تترك ترقية أحدهما دون الآخر مسار التحويل المصاب متاحًا. الإصلاح الدائم إزالة نقطة التضمين لا الأمل في فشل سلسلة المرشحات.
5. لماذا تتجاوز الدفاعات الشائعة
- لا حاجة لرفع ملف. تُولَّد الحمولة في الذاكرة، فلا تراها مجلدات الرفع ولا فحوص MIME ولا مكافحات الفيروسات.
- لا حاجة لمجلد قابل للكتابة. لا يحتاج المهاجم إلى إسقاط webshell.
- قواعد WAF التوقيعية تتعثر. العنوان سلسلة طويلة من أسماء مرشحات مشروعة؛ وحجب كل المتغيرات صعب دون حجب الاستخدام المشروع.
- يمكن أن تكون الحمولة صغيرة. وسم PHP قصير يكفي لاستدعاء
systemأوassertأو دالة مخصصة.
6. الكشف والتحصين
6.1 أزل التضمينات الديناميكية
لا تمرّر إدخال المستخدم مباشرة إلى include أو require أو include_once أو require_once. استخدم خريطة سماح:
<?php
$pages = [
'home' => __DIR__ . '/pages/home.php',
'about' => __DIR__ . '/pages/about.php',
'contact' => __DIR__ . '/pages/contact.php',
];
$key = $_GET['page'] ?? 'home';
if (!array_key_exists($key, $pages)) {
http_response_code(404);
exit;
}
include $pages[$key];
يزيل ذلك نقطة التضمين كليًا. فلا سلسلة مرشحات ولا حيلة ترميز ولا تسلسل مسار يمكنه اختيار ملف خارج الخريطة.
6.2 تحصين إعداد PHP
- اضبط
allow_url_include = Offوallow_url_fopen = Offإلا عند حاجة صريحة. - استخدم
open_basedirلتقييد الوصول إلى مجلد التطبيق. - عطّل الأغلفة غير المستخدمة حيث يسمح وقت التشغيل.
- شغّل PHP بمستخدم منخفض الصلاحية بلا وصول shell وبلا كتابة خارج مجلد الرفع.
6.3 صحّح حزمة التحويل
أبقِ glibc عند 2.40 أو أحدث على التوزيعات المصابة، وأبقِ PHP محدّثًا. وتتبّع CVE-2024-2961 في إدارة الثغرات حتى لو لم يستخدم التطبيق iconv مباشرة؛ فنظام مرشحات PHP يستطيع الوصول إليها.
6.4 اكشف التقنية
سجّل معاملات الطلبات التي تحتوي php://filter أو رموز convert.iconv متكررة أو سلاسل استعلام طويلة بشكل غير عادي. ونبّه على أخطاء التضمين التي تكشف استخدام الأغلفة. ويمكن لقاعدة WAF حجب السلاسل الواضحة، لكنها تخفيف لا إصلاح.
# مثال كشف في سجلات الويب (راجعه قبل النشر)
grep -E 'php://filter|convert\.iconv' /var/log/nginx/access.log | head
7. الخاتمة
تلغي سلاسل مرشحات PHP التمييز بين «قراءة ملف» و«تنفيذ شيفرة». نقطة التضمين هي الثغرة، وسلسلة المرشحات هي آلية التسليم. أظهرت CVE-2024-2961 أن مكتبة التحويل نفسها قد تصبح بدائية استغلال. والاستجابة الصحيحة ليست حجب سلسلة حمولة معينة بل إزالة التضمينات الديناميكية وتقييد نظام الملفات وتصحيح وقت التشغيل ومراقبة إساءة الأغلفة. وإذا أمكن دفع تطبيق لتضمين مسار يختاره المستخدم، فافترض أن المهاجم سيحوّل ذلك المسار إلى شيفرة في النهاية.