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。
能够在 Redis 上设置 cake_ 键,或写入缓存文件的人,可以植入一个序列化对象。下一次 Cache::read(或 CacheSession 加载)会在 PHP worker 中执行它。
| ID | 暂无 CVE |
| 类别 | 对象注入 |
| 可达性 | 当 Redis 或 Memcached 可被攻击者写入时为远程。对于 tmp/cache 上的 FileEngine 为本地。 |
| 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 或缓存文件)。不是对锁定 localhost Redis 的未认证 HTTP。 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
在应用缓存中植入一个序列化对象。下一次读取会在 worker 中执行 PHP。本实验止步于一个见证文件。它不演示 gadget 链或 shell。
实验已验证(完整性)
cake_<key> 然后 Cache::read。 默认前缀是 cake_。当 allowedClasses 为默认值 true 时,RedisEngine 的 unserialize() 使用裸 unserialize($value)。一个植入的 LabMarker 对象被实例化为 LabMarker,__wakeup 以 PHP UID 写入了见证文件。{expiry}\n{serialize($obj)}。 FileEngine::get() 仍然调用裸 unserialize($data)。相同的标记,相同的见证。文件名是 prefix 加键(cake_labfile)。allowedClasses => false 拒绝对象。 相同的 Redis 载荷返回为 __PHP_Incomplete_Class。__wakeup 未运行。见证文件不存在。推断(此处未实际利用)
defaults => cache 时,CacheSession::read 是同一个汇聚点。每次会话加载都会变成对攻击者控制的缓存字节的反序列化。serialize => php 是同一类漏洞。本实验未启动 Memcached。已排除 / 非此遗留问题
cakephp/app 的未认证 HTTP。allowedClasses => false(或严格列表)在运维人员设置时已能阻止对象。它不是默认值。同一版本遗留问题:window SQLi、collate SQLi、attachment CRLF。
在 2026 年 FunctionsBuilder / jsonValue / Smtp CRLF / View element 浪潮之后,我锁定了 cakephp/cakephp 5.4.2。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;交付 gadget 链;声称 FileEngine 是远程的;反弹 shell。都是表演。判定标准是一个标记 __wakeup 写入一个标志文件。
python3 cakephp-cache-unserialize-Abraxas-Labs.py
或
cd lab
./run.sh
目标仅为 127.0.0.1:19470。Docker 内来自标签 5.4.2 的实时 CakePHP 5.4.2。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.phpGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。