إلغاء تسلسل PHAR في منظومة ووردبريس: من رفع ملف بريء إلى تنفيذ شيفرة عن بُعد
غالبًا ما يُوصف حقن كائنات PHP بأنه ثغرة تتطلب استدعاءً مباشرًا لـ unserialize(). في الواقع، تعرض تطبيقات PHP الحديثة سطح إلغاء تسلسل ثانيًا أقل وضوحًا: غلاف تدفق PHAR. عندما ينفّذ التطبيق أي عملية على نظام الملفات تقريبًا على مسار phar://، فإن PHP يحلّل بيانات الأرشيف الوصفية ويلغي تسلسلها. لا حاجة لاستدعاء unserialize() صراحةً. تشرح هذه المقالة الآلية، وتفحص ثغرة ووردبريس المسماة CVE-2025-2105، وتوضح كيف يمكن للمدافعين تحديد نقطة الوصول والقضاء عليها.
1. حقن الكائنات في فقرة واحدة
تحوّل تسلسلات PHP الكائن إلى تدفق بايتات يسجّل اسم الصنف وخصائصه. ويعيد إلغاء التسلسل بناء ذلك الكائن. إذا تحكم المهاجم في التدفق، فإنه يتحكم في اسم الصنف وكل قيمة خاصية. الخطر لا يكمن في إعادة البناء ذاتها، بل في الدوال السحرية التي يستدعيها PHP تلقائيًا: __wakeup() و__destruct() و__toString() وغيرها. سلسلة من هذه الدوال عبر أصناف مشروعة — سلسلة أدوات POP — يمكن أن تحوّل رسم كائنات مزوّرًا إلى كتابة ملفات أو استعلامات SQL أو تنفيذ أوامر.
CVE-2025-2105 مثال نموذجي. أصابت إضافة Jupiter X Core لووردبريس حتى الإصدار 4.8.11 وتم إصلاحها في 4.8.12. يصنّفها الإشعار على أنها حقن كائنات PHP غير مصادَق عليه (CWE-502) بدرجة CVSS 8.1. العبرة ليست في اسم الإضافة، بل في أن طلبًا غير مصادَق عليه كان قادرًا على الوصول إلى بدائية إلغاء تسلسل في مكوّن لا يدقّقه كثير من مالكي المواقع.
2. لماذا يغيّر PHAR نموذج التهديد
أرشيف PHAR هو صيغة حزم خاصة بـ PHP. يحتوي على stub وبيانات وصفية ومحتويات الملفات. ويمكن للبيانات الوصفية تخزين بيانات مُسلسَلة. وفقًا لتوثيق PHP، يحلّل غلاف phar:// تلك البيانات عند فتح الأرشيف. إلغاء التسلسل أثر جانبي لاستدعاء عادي لنظام الملفات:
// أي من هذه الاستدعاءات قد يفعّل إلغاء تسلسل بيانات PHAR الوصفية
file_exists('phar:///var/www/uploads/avatar.jpg');
filesize('phar:///var/www/uploads/avatar.jpg');
getimagesize('phar:///var/www/uploads/avatar.jpg');
file_get_contents('phar:///var/www/uploads/avatar.jpg');
النتيجة العملية: تطبيق يقبل رفع ملف ثم يستدعي دالة نظام ملفات على مسار يؤثر فيه المستخدم قد يكون قابلًا للاستغلال حتى دون استدعاء unserialize(). لا يحتاج الملف إلى امتداد .phar، بل يكفي أن يكون أرشيف PHAR صالحًا يمكن دفع التطبيق لفتحه عبر الغلاف.
ملفات الرفع متعددة الصيغ
يمكن جعل أرشيف PHAR يبدو كصورة. قد يبدأ الملف برأس JPEG أو GIF صالح ويحتوي على بيانات PHAR لاحقًا. لذا فإن التحقق من البايتات الأولى فقط أو نوع MIME الذي يعلنه المتصفح أو الامتداد غير كافٍ. يجب ألا يبني الخادم مسار phar:// من إدخال المستخدم أبدًا.
3. بناء PHAR بسيط في المختبر
الشيفرة التالية مخصّصة لبيئة مختبر معزولة فقط. إنشاء PHAR يتطلب phar.readonly=0؛ ويجب أن تُبقي خوادم الإنتاج القيمة الافتراضية phar.readonly=1.
<?php
// lab-build-phar.php — شغّله بـ: php -d phar.readonly=0 lab-build-phar.php
class DemoGadget {
public $cmd = 'id';
public function __destruct() {
if (is_string($this->cmd)) {
system($this->cmd);
}
}
}
@unlink('/tmp/lab.phar');
$p = new Phar('/tmp/lab.phar');
$p->startBuffering();
$p->addFromString('x.txt', 'lab');
$p->setStub("<?php __HALT_COMPILER(); ?>");
$p->setMetadata(new DemoGadget());
$p->stopBuffering();
echo "PHAR written\n";
وفي الجانب المصاب، يكفي استدعاء واحد لإنشاء رسم الكائنات:
<?php
// lab-trigger.php
file_exists('phar:///tmp/lab.phar/x.txt');
تظهر نتيجة id عند تدمير الكائن. في اختبار حقيقي، سيكون صنف الأداة صنفًا موجودًا في التطبيق أو مكتبة مضمّنة، والهدف بدائية كتابة أو تنفيذ أوامر دون الاعتماد على صنف مخصص.
4. نمط CVE-2025-2105
يوضّح إصدار Jupiter X Core الخطأ المعماري نفسه على مستوى التطبيق: إدخال غير موثوق وصل إلى نقطة حقن كائنات. ثلاثة شروط جعلته خطيرًا:
- لا يتطلب مصادقة. كان المسار المصاب متاحًا قبل تسجيل الدخول، ما يزيل الشرط المسبق الأكثر شيوعًا للاستغلال.
- منظومة إضافات واسعة. تشحن إضافات ووردبريس أصنافًا كثيرة. وحتى إن لم تحتوِ الإضافة المصابة على أداة مفيدة، فقد يحتوي موقع بعشرات الإضافات على سلسلة كاملة.
- تبنٍّ صامت للتصحيح. بقي المستخدمون الذين عطّلوا التحديث التلقائي أو ثبّتوا إصدارًا قديمًا معرّضين بعد صدور الإصلاح.
تذكّرنا هذه الثغرة بأن حقن الكائنات يجب التعامل معه كفئة تنفيذ شيفرة عن بُعد، لا كمسألة كشف معلومات منخفضة الخطورة. وتعكس درجة CVSS 8.1 هذا التمييز.
5. تحديد نقاط إلغاء التسلسل أثناء مراجعة الشيفرة
ابدأ بالنقاط المباشرة، ثم وسّع إلى دوال نظام الملفات التي قد تستقبل مسار phar://:
# إلغاء تسلسل مباشر
grep -rn --include='*.php' -E '\b(unserialize|maybe_unserialize)\s*\(' .
# استدعاءات ملفات تدعم PHAR
grep -rn --include='*.php' -E '\b(file_exists|filesize|getimagesize|file_get_contents|file_put_contents|is_file|is_dir|stat|md5_file|sha1_file|copy|rename|unlink)\s*\(' .
# معالجات الرفع وبناء المسارات
grep -rn --include='*.php' -E '(move_uploaded_file|wp_handle_upload|\$_FILES)' .
لكل نتيجة، تتبّع الوسيط إلى مصدره. إذا كان أي جزء من المسار يتحكم فيه المستخدم ويمكن دفع الشيفرة لإضافة phar://، فالنقطة خطيرة. راقب خصوصًا معالجة الصور ومعالجات الصور الرمزية والاستيراد/التصدير وأي شيفرة تتحقق من ملف ثم تعيد فتحه بمساره.
التحقق وقت التشغيل
في المختبر، فعّل phar.readonly=1، وعطّل الغلاف فقط إذا تطلب ذلك خطة الاختبار، وضع نقطة توقف Xdebug على Phar::getMetadata(). إذا قُرئت البيانات الوصفية فقد أُنشئ رسم الكائنات بالفعل. هذه هي لحظة تأكيد الأصناف المتاحة ووجود سلسلة من عدمه.
6. ضوابط دفاعية فعّالة
- لا تبنِ مسار
phar://من إدخال. ثبّت مسار الرفع في دليل ثابت واستخدم اسمًا يولّده الخادم. وارفض أي مسار يحتوي على مخطط غلاف. - تحقق من المحتوى لا من التسمية. استخدم
finfoأوgetimagesize()على الملف المؤقت الحقيقي، وأعد ترميز الصور، وأزل البيانات الوصفية. رأس صورة صالح لا يثبت غياب بيانات PHAR. - أبقِ
phar.readonly=1. يمنع الإنشاء لا التحليل، لذا هو إجراء تقوية وليس إصلاحًا كاملًا. - عطّل الأغلفة غير المستخدمة. إذا لم يحتج التطبيق إلى PHAR، فأزل الغلاف من القائمة المسموحة وطبّق ذلك على مستوى خادم الويب.
- صحّح بسرعة واحصر الإضافات. أُصلحت CVE-2025-2105 في Jupiter X Core 4.8.12. حافظ على قائمة مكوّنات ووردبريس وأزل الإضافات المهجورة.
- طبّق أقل صلاحية لمستخدم الويب. عملية PHP لا تستطيع الكتابة خارج مجلد الرفع ولا تشغيل صدَفة تحدّ من أثر أي سلسلة أدوات.
7. الخاتمة
يذكّرنا إلغاء تسلسل PHAR بأن حدود الأمان تُحدَّد بتدفق البيانات لا بأسماء الدوال. قد يكون التطبيق مصابًا دون استدعاء unserialize() أبدًا؛ وقد يكون الملف الذي يشبه JPEG رسم كائنات مُسلسَلًا. تُظهر CVE-2025-2105 سرعة تحوّل بدائية حقن كائنات غير مصادَق عليها في إضافة ووردبريس واسعة الانتشار إلى خطر تنفيذ شيفرة. على المدافعين اعتبار كل استدعاء نظام ملفات على مسار يؤثر فيه المستخدم نقطة إلغاء تسلسل محتملة، وكل ملف مرفوع شيفرة غير موثوقة حتى يُعاد ترميزه ويُخزَّن باسم يتحكم به الخادم.