CakePHP 5.4.2 — высокий уровень — удалённо — десериализация — механизмы кэширования десериализуют объекты без списка разрешённых классов
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · 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 записал файл-свидетель от имени PHP UID.{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 — тот же класс ошибки. Эта лаборатория не запускала 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);
Уже зафиксированные неверные пути: трактовка защищённого localhost 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. Без шелла.
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 наследует политику unserialize движка кэша.
887b641de9f7aba06071f98f17edcbc573cbcf63)RedisEngine.php · FileEngine.phpGNU Affero GPL v3.0. См. LICENSE. Только лаборатория на loopback. Без гарантий.