
Exploit PoC di Snipe-IT per CVE-2025-59712 e CVE-2025-59713
Questo PoC fornisce uno script automatizzato per sfruttare CVE-2025-59712 (XSS nell'header User-Agent) e CVE-2025-59713 (deserializzazione non sicura).
Queste due vulnerabilità sono state scoperte da Synacktiv durante una ricerca sulle vulnerabilità del software Snipe-IT. Snipe-IT è un sistema open-source di gestione degli asset basato su Laravel e progettato per aiutare le organizzazioni a tracciare e gestire i propri asset fisici e digitali.
Un'analisi tecnica è disponibile nell'avviso di sicurezza dedicato sul sito di Synacktiv.
Questo script fornisce tre sottocomandi, corrispondenti alle modalità di sfruttamento: xss, rce e fullchain.
Questo sottocomando sfrutta CVE-2025-59712, che consente a un utente con privilegi limitati di iniettare JavaScript arbitrario nella pagina HTML generata quando si chiama la rotta /reports/activity. Questo è possibile solo per un utente admin, o per un utente che ha espliciti permessi di visualizzazione per i report. L'iniezione è possibile a causa di una sanitizzazione non corretta del campo User-Agent quando un utente aggiorna le proprie informazioni del profilo.
Per farlo, accederà prima come utente con privilegi limitati, e poi inietterà il codice JavaScript definito nel file fornito tramite il flag --javascript.
$ python3 exploit.py xss --help
Usage: exploit.py xss [OPTIONS]
Execute XSS attack only with custom JavaScript payload
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged username [required] │
│ * --password -p TEXT Low-privileged password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ * --javascript -js TEXT Path to custom JavaScript file [required] │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[!IMPORTANT]
Durante la ricerca di sicurezza, i test sono stati effettuati su una versione di Snipe-IT che, di default, visualizzava il campoUser-Agentin cui viene iniettato il JavaScript dannoso. Dal commit 10e5d88, la proprietàUser-Agentnon viene più visualizzata di default quando viene renderizzata la tabella del registro delle azioni. Pertanto, l'admin che attiverà la XSS deve aver spuntato la casellaUser-Agentnelle opzioni di visualizzazione per le versioni di Snipe-IT successive a questo commit.
Questo sottocomando sfrutta CVE-2025-59713, che consente l'esecuzione di codice remoto quando sono note le credenziali di un utente admin o superadmin. Per farlo, vengono eseguiti i seguenti passaggi:
db-dumps/mysql-snipeit.sql, che creano un nuovo campo personalizzato e modificano l'ultimo log delle azioni con un oggetto JSON contenente la pop chain di Laravel al momento del ripristino.[!TIP] Di default, Snipe-IT include il file
.envnel backup. Se lo script lo rileva, il valore diAPP_KEYviene visualizzato e il file.envviene salvato nella directory./output(è possibile specificare una posizione personalizzata per quel file con--output-dir).
[!CAUTION] Il ripristino di un backup disconnette tutti gli utenti connessi all'istanza.
/api/v1/reports/activity, che attiva la deserializzazione ed esegue la pop chain di Laravel.$ python3 exploit.py rce --help
Usage: exploit.py rce [OPTIONS]
Execute RCE attack only (requires existing admin account)
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --admin-user -au TEXT Admin username [required] │
│ * --admin-pass -ap TEXT Admin password [required] │
│ --output-dir -od PATH Output dir for .env file [default: /home/ninja/Téléchargements/snipe-it-advisory/exploit/output] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Il sottocomando fullchain mira a concatenare entrambe le vulnerabilità XSS e RCE. Corrisponde a uno scenario in cui si ha accesso solo a un utente con privilegi limitati e si vuole ottenere l'esecuzione di codice remoto. Questo funziona solo se l'utente che visita la pagina /reports/activity è un admin o un superadmin. Infatti, solo questi ruoli hanno i diritti per creare e ripristinare un backup, necessario per avvelenare il database e attivare successivamente la pop chain di Laravel.
Per farlo, lo script:
--command, come per la modalità RCE).User-Agent un tag <scr> per forzare il browser della vittima a caricare il template JavaScript dannoso./reports/activity, la XSS viene attivata e il JavaScript dannoso viene caricato ed eseguito dal browser della vittima. Da quel momento, vengono eseguiti gli stessi passaggi del modulo RCE, ma in JavaScript.Questa modalità utilizza diverse librerie JavaScript aggiuntive; tutti i crediti vanno ai rispettivi autori:
$ python3 exploit.py fullchain --help
Usage: exploit.py fullchain [OPTIONS]
Execute full attack chain: XSS -> Backup manipulation -> RCE
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged user's username [required] │
│ * --password -p TEXT Low-privileged user's password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ --ip -i TEXT HTTP server IP address (default: auto-detect) │
│ * --port -P INTEGER HTTP server port [required] │
│ --admin-user -au TEXT Admin username to create [default: admin_rce] │
│ --admin-pass -ap TEXT Admin password to create [default: password123] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Per eseguire questo script, esegui i seguenti comandi:
$ git clone https://github.com/synacktiv/CVE-2025-59712_CVE-2025-59713
$ cd CVE-2025-59712_CVE-2025-59713
$ python3 -m venv .venv && source .venv/bin/activate
$ python3 -m pip install -r requirements.txt
Viene fornito anche un Dockerfile per provare lo script e riprodurre lo sfruttamento della vulnerabilità. Esso scarica una versione vulnerabile di Snipe-IT, configura il database con php artisan e imposta due utenti:
admin con password predefinita AdminPassword123!lowpriv con password predefinita LowPrivUser123!Prima di avviare il container, i file .env e snipe-it.conf devono essere aggiornati con l'URL dell'istanza Snipe-IT:
$ sed -i 's|^APP_URL=.*|APP_URL=http://<IP>:<PORT>|' .env
$ sed -i 's|\(ServerName\s*\).*|\1http://<IP>:<PORT>|' snipe-it.conf
Il container può quindi essere avviato:
$ docker build . -t "snipe-it-cve"
$ docker run -p 80:80 --name "snipe-it-debian" snipe-it-cve:latest