CakePHP 5.4.2 – Hoch – Remote – Unserialize – Cache-Engines deserialisieren Objekte ohne Klassen-Allowlist
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cache-unserialize
Write-up: https://abraxaslabs.tech/research/cakephp-cache-unserialize
Klasse: Object Injection Reichweite: Remote (Redis/Memcached-Schreibzugriff) / Lokal (FileEngine)
CakePHP 5.4.2 (887b641) – Cake Software Foundation
5.3.7 führte aus diesem Grund Redis allowedClasses ein und beließ den Standardwert aus Gründen der Abwärtskompatibilität bei true (alle erlauben). RedisEngine ruft weiterhin ein blankes unserialize() auf, wenn dieser Standardwert gilt. FileEngine besitzt überhaupt keine Allowlist. MemcachedEngine setzt serialize weiterhin standardmäßig auf php.
Wer einen cake_-Schlüssel auf Redis SETZEN oder eine Cache-Datei schreiben kann, platziert ein serialisiertes Objekt. Der nächste Cache::read (oder ein CacheSession-Ladevorgang) führt es im PHP-Worker aus.
| ID | noch keine CVE |
| Klasse | Object Injection |
| Reichweite | Remote, wenn Redis oder Memcached vom Angreifer beschreibbar ist. Lokal für FileEngine unter tmp/cache. |
| CWE | CWE-502 |
| CVSS | Hoch: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (erfordert Schreibzugriff auf den Cache-Store). FileEngine ist AV:L. |
| Produkt | CakePHP |
| Betroffen | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | Schreibzugriff auf den Cache-Store (Redis SET, Memcached set oder eine Cache-Datei). Kein unauthentifizierter HTTP-Zugriff auf ein abgesichertes lokales Redis. |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Ein serialisiertes Objekt im App-Cache platzieren. Der nächste Lesevorgang führt PHP im Worker aus. Dieses Lab endet bei einer Witness-Datei. Es demonstriert weder eine Gadget-Chain noch eine Shell.
Im Lab nachgewiesen (Integrität)
cake_<key> und dann Cache::read. Das Standardpräfix ist cake_. RedisEngine unserialize() verwendet ein blankes unserialize($value), wenn allowedClasses den Standardwert true hat. Ein platziertes LabMarker-Objekt, instanziiert als LabMarker, und __wakeup schrieben die Witness-Datei unter der PHP-UID.{expiry}\n{serialize($obj)} unter dem Cache-Pfad. FileEngine::get() ruft weiterhin ein blankes unserialize($data) auf. Gleicher Marker, gleiche Witness-Datei. Der Dateiname ist prefix plus Schlüssel (cake_labfile).allowedClasses => false verweigert Objekte. Dieselbe Redis-Payload kam als __PHP_Incomplete_Class zurück. __wakeup wurde nicht ausgeführt. Die Witness-Datei fehlte.Abgeleitet (hier nicht ausgeführt)
CacheSession::read ist dieselbe Senke, wenn die Session defaults => cache verwendet. Jeder Session-Ladevorgang wird zu einem Unserialize von angreiferkontrollierten Cache-Bytes.serialize => php ist dieselbe Fehlerklasse. Dieses Lab hat Memcached nicht gestartet.Geschlossen / nicht dieser Überrest
cakephp/app, das Redis nicht exponiert.allowedClasses => false (oder eine enge Liste) blockiert Objekte bereits, wenn ein Betreiber es setzt. Es ist nicht der Standard.Gleiche Pin-Überbleibsel: window SQLi, collate SQLi, attachment CRLF.
Ich habe cakephp/cakephp 5.4.2 nach der Welle um FunctionsBuilder / jsonValue / Smtp CRLF / View-Elemente aus dem Jahr 2026 gepinnt. RedisEngine dokumentiert die Option und lässt sie standardmäßig weiterhin offen:
* - `allowedClasses` ... Defaults to `true` (allow all) for backwards compatibility.
...
'allowedClasses' => true,
Lesepfad:
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 hat keine entsprechende Option:
if ($data !== '' && !empty($this->_config['serialize'])) {
$data = unserialize($data);
Bereits erfasste Fehlversuche: die Behandlung eines abgeriegelten lokalen Redis als unauth HTTP RCE; das Ausliefern einer Gadget-Chain; die Behauptung, FileEngine sei remote; eine Reverse Shell. Theater. Das Orakel ist ein Marker __wakeup, der eine Flag-Datei schreibt.
python3 cakephp-cache-unserialize-Abraxas-Labs.py
oder
cd lab
./run.sh
Ziel nur 127.0.0.1:19470. Live CakePHP 5.4.2 aus Tag 5.4.2 in Docker. Redis 7 mit deaktiviertem protected-mode, damit der Host SET ausführen kann. PHP 8.3 mit ext-redis. Marker-Klasse LabMarker mit __wakeup, die /tmp/CAKEPHP-CACHE-UNSERIALIZE-WITNESS schreibt. Keine 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
Setzen Sie den Standardwert für allowedClasses von Redis auf false oder auf eine eng begrenzte Liste von Klassen, die die Anwendung tatsächlich speichert. Fügen Sie dieselbe Option zu FileEngine hinzu und berücksichtigen Sie sie in get(). Setzen Sie den Standardwert für serialize von Memcached auf json. Dokumentieren Sie, dass CacheSession die Unserialize-Richtlinie der Cache-Engine erbt.
887b641de9f7aba06071f98f17edcbc573cbcf63)RedisEngine.php · FileEngine.php