
Kit de detección para CVE-2026-35616, una omisión de API de preautenticación en FortiClient EMS. Incluye un escáner en Python y un script NSE de Nmap para identificar versiones vulnerables y proporcionar orientación de remediación.
Un bypass de autenticación crítico en Fortinet FortiClient EMS 7.4.5 y 7.4.6 permite a un atacante remoto completamente no autenticado eludir la autenticación de la API falsificando una única cabecera HTTP (X-SSL-CLIENT-VERIFY). La falla existe porque el middleware de Django confía en los metadatos del certificado del cliente provenientes de cabeceras controladas por el usuario, no solo del proxy inverso de confianza. Esto otorga a los atacantes acceso administrativo completo a la API, y desde allí, ejecución arbitraria de código en los endpoints gestionados de toda la empresa.
Explotado activamente desde el 31 de marzo de 2026. Añadido al catálogo KEV de CISA el 6 de abril de 2026.
| Campo | Detalle |
|---|---|
| ID CVE | CVE-2026-35616 |
| Proveedor | Fortinet |
| Producto | FortiClient Enterprise Management Server (EMS) |
| Versiones Afectadas | 7.4.5, 7.4.6 |
| No Afectadas | Rama 7.2.x, 7.4.4 y anteriores |
| CVSS v3.1 | 9.1 (Crítico) |
| CWE | CWE-284 - Control de Acceso Inadecuado |
| Vector de Ataque | Red |
| Autenticación | No se requiere |
| Interacción del Usuario | Ninguna |
| Madurez del Exploit | Explotado en la naturaleza |
| CISA KEV | Añadido el 6 de abril de 2026 (fecha límite: 9 de abril de 2026) |
| Parche | Hotfix disponible; corrección completa en 7.4.7 |
| Créditos | Simo Kohonen (Defused Cyber), Nguyen Duc Anh |
FortiClient Enterprise Management Server (EMS) es la plataforma centralizada de gestión de endpoints de Fortinet. Actúa como la capa de comando y control para implementar, configurar y monitorear los agentes de FortiClient en una organización. Piense en él como el cerebro que gobierna cada endpoint en un entorno gestionado por Fortinet:
Cuando un atacante obtiene acceso administrativo a EMS, esencialmente posee las llaves de cada endpoint gestionado en la organización.
FortiClient EMS utiliza una pila de aplicaciones web bastante estándar entre bastidores:
+----------------+ +----------------+ +----------------+
| Navegador / | HTTPS | Apache | WSGI | Django |
| Cliente API | -------> | (mod_ssl) | -------> | Backend |
+----------------+ +----------------+ +----------------+
Cuando se configura TLS mutuo (mTLS), el mod_ssl de Apache maneja la verificación del certificado del cliente. Después de validar el certificado, Apache pasa el resultado de la verificación a Django a través de variables de entorno WSGI de confianza:
SSL_CLIENT_VERIFY - El estado de verificación (SUCCESS, NONE, FAILED)SSL_CLIENT_S_DN - El Nombre Distinguido del Sujeto del certificadoSSL_CLIENT_SERIAL - El número de serie del certificadoEste es el patrón estándar y seguro. El problema está en cómo el middleware de Django lee estos datos.
En FortiClient EMS 7.4.5 y 7.4.6, el middleware de autenticación de Django fue modificado para aceptar también esta misma información desde cabeceras de solicitud HTTP:
X-SSL-CLIENT-VERIFYX-SSL-CLIENT-S-DNX-SSL-CLIENT-SERIALEsto probablemente se añadió para soportar implementaciones con proxy inverso donde Apache no es el punto de terminación TLS. Sin embargo, el middleware no distingue entre estas dos fuentes. Primero verifica las variables WSGI, pero si están ausentes (sin mTLS configurado, o una conexión directa), recurre a las cabeceras HTTP, que cualquier cliente puede establecer.
Aquí está el desglose conceptual:
RUTA SEGURA (prevista):
Apache mod_ssl valida el certificado --> establece variables de entorno WSGI --> Django lee las variables de entorno [OK]
RUTA INSEGURA (la vulnerabilidad):
El atacante establece cabeceras HTTP directamente --> Django lee las cabeceras --> Confía en ellas [FALLO]
El middleware efectivamente confía en que el cliente auto-certifique su propio estado de verificación de certificado. Es como si un portero le preguntara a alguien "Oye, ¿el otro portero ya revisó tu identificación?" y lo dejara entrar cuando dice "sí".
Paso 1: El atacante envía una solicitud POST a un endpoint de la API de EMS
con estas cabeceras:
X-SSL-CLIENT-VERIFY: SUCCESS
X-SSL-CLIENT-S-DN: CN=admin
X-SSL-CLIENT-SERIAL: 0000000000000001
Paso 2: El middleware de Django verifica las variables de entorno WSGI → no presentes
Recurre a las cabeceras HTTP → encuentra X-SSL-CLIENT-VERIFY: SUCCESS
Paso 3: El middleware trata la solicitud como autenticada con identidad de administrador
Paso 4: El atacante tiene acceso administrativo completo a la API
Paso 5: Desde la API de administración, el atacante puede:
- Enviar políticas maliciosas a todos los endpoints gestionados
- Extraer credenciales y certificados almacenados
- Implementar payloads mediante la distribución de software
- Modificar configuraciones ZTNA
- Moverse lateralmente hacia la red más amplia
Todo el ataque requiere una única solicitud HTTP. Sin fuerza bruta, sin relleno de credenciales, sin ingeniería social. Solo una cabecera falsificada.
La gravedad aquí va más allá del propio servidor. FortiClient EMS es un multiplicador de fuerza: comprometerlo le da a un atacante influencia sobre cada endpoint gestionado:
Impacto Inmediato:
Impacto Descendente (a través de endpoints gestionados):