CakePHP 5.4.2 — высокий уровень — удалённо — десериализация — механизмы кэширования десериализуют объекты без списка разрешённых классов
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cache-unserialize
Разбор: https://abraxaslabs.tech/research/cakephp-cache-unserialize
Класс: Внедрение объектов Доступ: Удалённый (запись в 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-воркере.
| ID | CVE пока нет |
| Класс | Внедрение объектов |
| Доступ | Удалённый, когда 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 к защищённому localhost Redis. |
| Лицензия | GNU Affero GPL v3.0 |
| Лаборатория | только 127.0.0.1 |
Внедрить сериализованный объект в кэш приложения. Следующее чтение выполнит PHP в воркере. Эта лаборатория останавливается на файле-свидетеле. Она не демонстрирует цепочку гаджетов или получение оболочки.
Доказано в лаборатории (целостность)
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. Каждая загрузка сессии становится десериализацией байтов кэша, контролируемых атакующим.serialize => php — тот же класс ошибки. Эта лаборатория не запускала Memcached.Закрыто / не относится к этому остатку
cakephp/app, который не предоставляет доступ к Redis.allowedClasses => false (или строгий список) уже блокирует объекты, когда оператор его задаёт. Но это не значение по умолчанию.Оставшиеся закреплённые находки: 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 как неаутентифицированного HTTP RCE; поставка цепочки гаджетов; утверждение, что FileEngine является удалённым; обратная оболочка. Театр. Оракул — это маркер __wakeup, который записывает файл флага.
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
По умолчанию установить для Redis allowedClasses значение false или ограничить его узким списком классов, которые приложение действительно сохраняет. Добавить ту же опцию в FileEngine и учитывать её в get(). По умолчанию установить для Memcached serialize значение json. Задокументировать, что CacheSession наследует политику десериализации механизма кэша.
887b641de9f7aba06071f98f17edcbc573cbcf63)RedisEngine.php · FileEngine.php