CakePHP 5.4.2 - عالي - عن بُعد - Unserialize - محركات التخزين المؤقت تقوم بإلغاء تسلسل الكائنات دون قائمة فئات مسموح بها
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cache-unserialize
التحليل المكتوب: https://abraxaslabs.tech/research/cakephp-cache-unserialize
الفئة: حقن كائنات (Object injection) الوصول: عن بُعد (كتابة إلى Redis/Memcached) / محلي (FileEngine)
CakePHP 5.4.2 (887b641) - Cake Software Foundation
أضافت النسخة 5.3.7 خيار Redis allowedClasses لهذا السبب وأبقت القيمة الافتراضية على true (السماح للكل) من أجل التوافق مع الإصدارات السابقة. لا يزال RedisEngine يستدعي unserialize() المجرّدة عندما تكون هذه القيمة الافتراضية سارية. أما FileEngine فلا يملك أي قائمة سماح على الإطلاق. ولا يزال MemcachedEngine يعيّن serialize افتراضيًا إلى php.
من يستطيع تعيين مفتاح cake_ على Redis، أو كتابة ملف ذاكرة مؤقتة، يزرع كائنًا مُسلسَلًا. عند الاستدعاء التالي لـ Cache::read (أو تحميل CacheSession) يُنفَّذ ذلك الكائن داخل عامل PHP.
| المعرّف | لا يوجد CVE بعد |
| الفئة | حقن كائنات (Object injection) |
| الوصول | عن بُعد عندما يكون Redis أو Memcached قابلًا للكتابة من المهاجم. محلي بالنسبة لـ FileEngine على tmp/cache. |
| CWE | CWE-502 |
| CVSS | مرتفع: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (يتطلب الكتابة إلى مخزن الذاكرة المؤقتة). FileEngine هو AV:L. |
| المنتج | CakePHP |
| المتأثر | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| المصادقة | الكتابة إلى مخزن الذاكرة المؤقتة (Redis SET، أو Memcached set، أو ملف ذاكرة مؤقتة). وليس HTTP غير مُصادَق إلى Redis محلي مؤمَّن. |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
زرع كائن مُسلسَل في ذاكرة التطبيق المؤقتة. عند القراءة التالية يُنفَّذ PHP داخل العامل. يتوقف هذا المختبر عند ملف إثبات. ولا يُظهر سلسلة أدوات (gadget chain) أو صدفة (shell).
مُثبَت في المختبر (السلامة)
cake_<key> ثم Cache::read. البادئة الافتراضية هي cake_. يستخدم unserialize() في RedisEngine الاستدعاء المجرّد unserialize($value) عندما تكون allowedClasses على القيمة الافتراضية true. كائن LabMarker المزروع، الذي أُنشئ باسم LabMarker، كتب عبر __wakeup ملف الإثبات بصلاحيات UID الخاص بـ PHP.{expiry}\n{serialize($obj)} تحت مسار الذاكرة المؤقتة. لا يزال FileEngine::get() يستدعي unserialize($data) المجرّدة. نفس العلامة، نفس الإثبات. اسم الملف هو prefix مضافًا إليه المفتاح (cake_labfile).allowedClasses => false يرفض الكائنات. عادت نفس الحمولة الخاصة بـ Redis بصيغة __PHP_Incomplete_Class. لم يُنفَّذ __wakeup. وكان ملف الإثبات غائبًا.مُستنتَج (لم يُجرَّب هنا)
CacheSession::read هو نفس نقطة الوصول عندما تكون الجلسة defaults => cache. يصبح كل تحميل جلسة عملية unserialize لبايتات ذاكرة مؤقتة يتحكم بها المهاجم.serialize => php في MemcachedEngine هو نفس فئة الثغرة. لم يشغّل هذا المختبر Memcached.مُغلق / ليس من هذه البقايا
cakephp/app القياسي الذي لا يكشف Redis.allowedClasses => false في Redis (أو قائمة ضيقة) يحجب الكائنات بالفعل عندما يعيّنها المشغّل. لكنها ليست القيمة الافتراضية.بقايا التثبيت نفسها: window SQLi، collate SQLi، attachment CRLF.
ثبّتُّ cakephp/cakephp 5.4.2 بعد موجة 2026 الخاصة بـ FunctionsBuilder / jsonValue / Smtp CRLF / View element. يوثّق RedisEngine هذا الخيار ولا يزال يجعله مفتوحًا افتراضيًا:
* - `allowedClasses` ... Defaults to `true` (allow all) for backwards compatibility.
...
'allowedClasses' => true,
اقرأ المسار:
protected function unserialize(string $value): mixed
{
if (preg_match('/^[-]?\d+$/', $value)) {
return (int)$value;
}
$allowedClasses = $this->getConfig('allowedClasses');
if ($allowedClasses !== true) {
return unserialize($value, ['allowed_classes' => $allowedClasses]);
}
return unserialize($value);
}
FileEngine ليس لديه خيار مكافئ:
if ($data !== '' && !empty($this->_config['serialize'])) {
$data = unserialize($data);
المنعطفات الخاطئة المسجّلة بالفعل: التعامل مع Redis المحلي المُقفل كـ unauth HTTP RCE؛ شحن سلسلة gadget؛ الادعاء بأن FileEngine عن بُعد؛ reverse shell. مسرح. الـ oracle هو علامة __wakeup تكتب ملف flag.
python3 cakephp-cache-unserialize-Abraxas-Labs.py
أو
cd lab
./run.sh
استهدف فقط 127.0.0.1:19470. نسخة CakePHP 5.4.2 حيّة من الوسم 5.4.2 داخل Docker. Redis 7 مع إيقاف protected-mode حتى يتمكن المضيف من تنفيذ SET. PHP 8.3 مع ext-redis. صنف العلامة LabMarker مع __wakeup يكتب /tmp/CAKEPHP-CACHE-UNSERIALIZE-WITNESS. بدون shell.
SUCCESS cakephp-cache-unserialize redis-default-wakeup=yes redis-denied-wakeup=no file-wakeup=yes pin=5.4.2 sha=887b641de9f7aba06071f98f17edcbc573cbcf63 how=live CAKEPHP-CACHE-UNSERIALIZE-WITNESS
اجعل allowedClasses في Redis افتراضيًا false، أو قائمة محدودة من الفئات التي يخزّنها التطبيق فعليًا. أضف الخيار نفسه إلى FileEngine وطبّقه في get(). اجعل serialize في Memcached افتراضيًا json. وثّق أن CacheSession يرث سياسة إلغاء التسلسل الخاصة بمحرك التخزين المؤقت.
887b641de9f7aba06071f98f17edcbc573cbcf63)RedisEngine.php · FileEngine.phpGNU Affero GPL v3.0. راجع LICENSE. للاستخدام في مختبر loopback فقط. دون أي ضمان.