
إثبات مفهوم محلي آمن لثغرة حقن كائنات PHP في Cotonti CommentsWidget (CAN-2026-2035973 / CVE-2026-71294).
إثبات مفهوم محلي آمن لمسألة حقن كائنات PHP المُحدَّدة في تطبيق CommentsWidget الخاص بـ Cotonti.
plugins/comments/inc/CommentsWidget.phpيقبل مسار الكود المصاب معامل GET باسم ci ويمرّر بيانات يتحكم بها المهاجم عبر base64_decode() إلى دالة unserialize() في PHP دون تقييد الفئات التي يمكن إنشاؤها.
من الناحية المفاهيمية، العملية المصابة هي:
$ci = @unserialize(base64_decode($ci));
عند تمرير كائن مُسلسَل، قد يُنشئ PHP الفئة التي يتحكم بها المهاجم ويستدعي الدوال السحرية مثل __wakeup(). في تطبيق أكبر، قد يصبح هذا خطيرًا عند توفر فئات gadget مناسبة.
يغيّر الإصلاح المُقدَّم إلغاء التسلسل إلى:
$ci = @unserialize(base64_decode($ci), ['allowed_classes' => false]);
ويتحقق من أن القيمة الناتجة تمتلك بنية المصفوفة المتوقعة قبل استخدامها.
ينفّذ poc.php ثلاثة اختبارات محلية:
unserialize() غير المقيّدة بإنشاء DangerousGadget وتشغيل دالة __wakeup() الخاصة به.allowed_classes => false إنشاء فئة gadget وبالتالي يمنع الأثر الجانبي لـ __wakeup().يستخدم الإثبات /tmp/pwned_by_cotonti_poc.txt فقط كعلامة غير ضارة تُظهر أن __wakeup() قد نُفِّذت. وهو لا ينفّذ أمرًا على نظام التشغيل. السلسلة id && whoami موجودة فقط كقيمة بديلة في خاصية command الخاصة بـ gadget.
serialize() / unserialize()لا يلزم تثبيت Cotonti لأن سلوك إلغاء التسلسل المصاب والمُصلَح يُعاد إنتاجه مباشرة.
من دليل المستودع:
php poc.php
المخرجات المتوقعة مشابهة لـ:
[!] DangerousGadget::__wakeup() triggered
[TEST 1] VULNERABLE: __wakeup() executed during unrestricted unserialize().
[TEST 2] FIXED: object instantiation was blocked; no sentinel was created.
[TEST 3] FIXED: invalid serialized structure rejected by validation.
Summary:
- Vulnerable path allows a serialized attacker-controlled object to be instantiated and invokes __wakeup().
- Fixed path uses allowed_classes=false, preventing the gadget class from being instantiated.
- Structural validation rejects values that do not match the expected array shape.
- No real command execution is performed by this PoC; the command property is only a placeholder.
يحذف السكربت ملف العلامة الخاص به قبل الخروج.
لا تقم بإلغاء تسلسل بيانات يتحكم بها المهاجم باستخدام unserialize() في PHP دون قيود.
بالنسبة لمسار الكود هذا، التخفيف الموضّح هو تعطيل إنشاء الفئات:
unserialize($data, ['allowed_classes' => false]);
يجب أيضًا التحقق من القيمة المُلغَى تسلسلها مقابل البنية الدقيقة المتوقعة من التطبيق قبل استخدام محتوياتها.
هذا المستودع مخصص للبحث الأمني والتحقق والاختبار الدفاعي. شغّل الإثبات فقط في البيئات التي تملكها أو المصرّح لك صراحةً باختبارها. لا تستخدمه لاستهداف أنظمة دون إذن.
Harsh Raj Singhania — بحث الثغرة، وإثبات المفهوم، والإفصاح.