
Script de detección para CVE-2026-11374
Un script de detección para la precondición de explotación de CVE-2026-11374, una falla predecible de tickets SSO que permite la toma de control de cuentas sin autenticación en la suite ManageEngine AD360. Los cuatro productos dentro del alcance comparten el ManageEngineADSFramework:
| Producto | Compilación afectada | Compilación corregida |
|---|
| ADSelfService Plus | ≤ 6528 | 6529 |
| RecoveryManager Plus | ≤ 6320 | 6321 |
| M365 Manager Plus | ≤ 4816 | 4817 |
| ADAudit Plus | ≤ 8702 | 8703 |
En las compilaciones afectadas, el ticket SSO es simplemente System.currentTimeMillis() (una marca de tiempo predecible) muestreada en el inicio de sesión de la víctima, por lo que puede reproducirse mediante la cookie CUSTOM_SSO_TICKET para secuestrar esa sesión. La corrección reemplaza el ticket con UUID.randomUUID() (un identificador suficientemente aleatorio). La ruta de reproducción solo es alcanzable cuando el producto está integrado con AD360: ADSFilter la condiciona con isProductIntegrated(). Esa condición es la precondición que esta herramienta comprueba.
NOTA: este detector confirma la precondición, no la vulnerabilidad en sí. Un resultado
POTENTIALLY_AFFECTEDno es un veredicto de vulnerable confirmado; consulte más abajo para más información.
Sí. Está diseñado para uso en producción y en evaluaciones.
1700000000000, un valor en milisegundos lo suficientemente lejano en el pasado como para que nunca pueda estar en caché), por lo que nunca se recupera ninguna sesión. El servidor solo nos indica que borremos las cookies que enviamos.GET simple, y las únicas cookies afectadas son las desechables que envía la herramienta.El parche de CVE-2026-11374 solo cambió la forma en que se genera el ticket (milisegundos a UUID); no cambió la ruta de reproducción de cookies que esta sonda ejercita. Como resultado, una instalación parcheada responde byte por byte de manera idéntica a una vulnerable para cualquier solicitud no autenticada.
Lo que la herramienta puede hacer, sin autenticación y de forma no destructiva:
Lo que no puede hacer:
POTENTIALLY_AFFECTED significa que la precondición se cumple y que debe verificar el nivel de parche, no que el host esté confirmado como vulnerable.conf/product.conf localmente, o resolver activamente un ticket en vivo (explotación real, intencionalmente no implementada aquí).?build= de ADSSP a veces es la compilación real y a veces un marcador congelado que lee por debajo de la compilación corregida, por lo que un valor inferior al corregido es ambiguo y la herramienta lo marca como no concluyente. Un valor igual o superior a la compilación corregida sigue siendo una señal confiable de parcheado, ya que el marcador siempre es demasiado bajo para alcanzarlo.requests. Instale con
pip install requests.# un solo host (prefiera una URL o host:puerto; los puertos difieren según el producto)
./cve_2026_11374_check.py https://adssp.example.com:8888
# múltiples hosts (el esquema es opcional: se prueba https primero, luego http)
./cve_2026_11374_check.py host-a:8081 host-b:8365
# escanear una lista, un objetivo por línea (se permiten comentarios con '#'), salida compacta
./cve_2026_11374_check.py -f targets.txt --brief
# salida legible por máquina para canalizaciones
./cve_2026_11374_check.py -f targets.txt --json > results.json
Los puertos predeterminados difieren según el producto (ADSelfService Plus 8888, ADAudit Plus 8081, M365 Manager Plus 8365, RecoveryManager Plus 8090), así que pase una URL o host:puerto. Un host sin puerto usa 8888 por defecto.
| Bandera | Descripción |
|---|---|
targets | Uno o más host, host:puerto o https://host:puerto |
-f, --targets-file ARCHIVO | Leer objetivos desde un archivo (uno por línea; comentarios con #) |
--brief | Una línea alineada por objetivo, útil para escanear muchos hosts |
--json | Emitir resultados JSON estructurados |
--timeout SEGS | Tiempo de espera por solicitud (predeterminado: 15) |
--no-build | Omitir la solicitud adicional de número de compilación en un hallazgo positivo |
--no-color | Deshabilitar la salida de color (también respeta NO_COLOR y no-TTY) |
Una consola integrada con AD360 (verboso, el predeterminado). La segunda línea aclara que esto es la precondición y no un veredicto de vulnerable; la tercera es la pista de compilación de mejor esfuerzo:
$ ./cve_2026_11374_check.py https://adssp.example.com:8888
[!] https://adssp.example.com:8888: POTENTIALLY_AFFECTED
ADSelfService Plus: integrado con AD360, ruta de reproducción CustomSSO activa - precondición cumplida. No confirmado como vulnerable; verifique el nivel de parche (compilación corregida 6529).
compilación: 6519 (por debajo de la corregida 6529 - no concluyente: ?build= puede ser un marcador obsoleto o un hotfix)
Una instalación independiente del mismo producto, donde la ruta de reproducción no está activa:
$ ./cve_2026_11374_check.py https://adssp.example.com:8888
[+] https://adssp.example.com:8888: UNAFFECTED
ADSelfService Plus: independiente / no integrado con AD360 (sin limpieza), por lo que la ruta de reproducción no es alcanzable aquí. Verifique build >= 6529 de todos modos.
Escaneo de una lista con una línea alineada por host (--brief). El estado de salida es 1 si algún host es POTENTIALLY_AFFECTED; de lo contrario 0, lo cual es útil en scripts. La nota final muestra el producto identificado, además del número de compilación en un hallazgo:
$ ./cve_2026_11374_check.py -f targets.txt --brief; echo "exit: $?"
POTENTIALLY_AFFECTED https://host-a:8888 ADSelfService Plus 6519
POTENTIALLY_AFFECTED http://host-b:8081 ADAudit Plus 8530
UNAFFECTED http://host-c:8365 M365 Manager Plus
UNAFFECTED https://host-d:443
INCONCLUSIVE http://host-e:8888 ADSelfService Plus
ERROR host-f:8888 timeout
exit: 1
Salida legible por máquina (--json). Cada resultado incluye el verdict, el state y detail que lo respaldan, el product identificado y, en un hallazgo, un objeto build: build es el número encontrado, fixed_build el umbral para ese producto, patch_hint la llamada direccional (likely_patched si es igual o superior a la compilación corregida, de lo contrario inconclusive), y note una breve explicación:
$ ./cve_2026_11374_check.py https://host-b:8081 --json
[
{
"target": "https://host-b:8081",
"state": "potentially_affected",
"detail": "ADAudit Plus: integrado con AD360, ruta de reproducción CustomSSO activa - precondición cumplida ...",
"product": "ADAudit Plus",
"build": { "build": "8530", "fixed_build": "8703", "patch_hint": "inconclusive", "note": "por debajo de 8703 - no concluyente: puede ser un hotfix" },
"verdict": "POTENTIALLY_AFFECTED"
}
]
| Veredicto | Significado |
|---|---|
POTENTIALLY_AFFECTED | Producto dentro del alcance integrado con AD360; la ruta de reproducción de cookies CustomSSO está activa, por lo que se cumple la precondición de explotación de CVE-2026-11374. Esto no es un veredicto de vulnerable confirmado; verifique el nivel de parche (consulte los siguientes pasos). |
UNAFFECTED | La ruta de reproducción no es alcanzable. Cualquiera de: un producto dentro del alcance independiente (no integrado con AD360 — aunque sería alcanzable si se integrara más tarde, así que verifique la compilación de todos modos); un producto del framework ADS de ManageEngine que no sea uno de los cuatro dentro del alcance; o ningún producto dentro del alcance en la respuesta (no uno de los cuatro productos de CVE-2026-11374, o un proxy que elimina la cookie de sesión). |
INCONCLUSIVE | Un HTTP 400 — probablemente el bloqueo por límite de velocidad de IAM enmascarando la señal; reintente después de ~60 s. |
ERROR | Fallo de conexión/timeout/TLS. |
| Código | Significado |
|---|---|
0 | Ningún objetivo devolvió POTENTIALLY_AFFECTED |
1 | Al menos un objetivo es POTENTIALLY_AFFECTED |
2 | Error de uso (argumentos incorrectos / archivo de objetivos ilegible) |
Envíe un ticket no válido más una etiqueta de aplicación a cualquier URL CustomSSO (*.do):
GET /AppsHome.do
Cookie: CUSTOM_SSO_TICKET=1700000000000; CUSTOM_SSO_APP_TAG_NAME=AD360
En una instalación integrada con AD360, la cadena ADSFilter → CustomSSOFilter → CookieSSOImpl ejecuta su rama de resolución (la etiqueta nombra un producto diferente, por lo que appName != prodName), falla al resolver el ticket falso y emite encabezados de respuesta de limpieza de cookies:
Set-Cookie: CUSTOM_SSO_TICKET=removed; Max-Age=0; ...
Set-Cookie: CUSTOM_SSO_APP_NAME=removed; Max-Age=0; ...
Set-Cookie: CUSTOM_SSO_APP_TAG_NAME=removed; Max-Age=0; ...
Una instalación independiente nunca ejecuta esa ruta y no emite limpieza. El producto se identifica por su cookie de sesión Tomcat fija específica del producto (JSESSIONIDADSSP para ADSelfService Plus, y así sucesivamente), que se establece en cada respuesta. La comprobación se basa en los encabezados y no en el código de estado, ya que un ADSSP integrado devuelve un 302 mientras que ADAudit, M365 y RMP devuelven 200 ante la misma sonda.
| Respuesta de la sonda | Veredicto |
|---|---|
| encabezados de limpieza y una cookie de producto conocida dentro del alcance | POTENTIALLY_AFFECTED |
| cookie de producto, sin limpieza, estado ≠ 400 | UNAFFECTED (independiente / no integrado) |
| sin cookie de producto dentro del alcance, estado ≠ 400 | UNAFFECTED (no es uno de los cuatro productos) |
| encabezados de limpieza pero cookie de producto no reconocida | UNAFFECTED (ManageEngine, fuera del alcance) |
HTTP 400 | INCONCLUSIVE (probablemente el bloqueo por límite de velocidad de IAM; consulte Limitaciones) |
POTENTIALLY_AFFECTED no es "vulnerable confirmado". Es la precondición de explotación. Debido a que el parche no tocó esta ruta de código, una compilación parcheada responde de manera idéntica, por lo que debe confirmar el nivel de parche fuera de banda (consulte los siguientes pasos). Ese es el techo de lo que un observador no autenticado puede saber.HTTP 400 puede ser un bloqueo por límite de velocidad en lugar de una respuesta real. Zoho IAM aplica un throttling rotatorio de URL que limita una IP de origen a alrededor de 40 solicitudes por 60 s, y luego bloquea esa ruta durante ~60 s. Durante un bloqueo, las solicitudes devuelven HTTP 400 y la señal de integración queda enmascarada. La herramienta las reporta como INCONCLUSIVE; reintente desde esa IP después de aproximadamente un minuto.UNAFFECTED. Confirme directamente si espera un producto ManageEngine allí.?v=) y M365 (?bN=) siempre exponen la compilación real; el ?build= de ADSSP a veces es real y a veces un marcador congelado que lee por debajo de la compilación corregida, por lo que un valor de ADSSP inferior al corregido es ambiguo; RMP no expone ninguno. En todos los casos, una compilación igual o superior a la corregida indica fuertemente que está parcheado, y por debajo de ella es no concluyente.Si un objetivo devuelve POTENTIALLY_AFFECTED, trátelo como expuesto y digno de confirmación, luego:
Confirme el nivel de parche directamente (la herramienta no puede). Lea conf/product.conf (build_number) en el host y compárelo con la compilación corregida para ese producto (ADSelfService Plus 6529, RecoveryManager Plus 6321, M365 Manager Plus 4817, ADAudit Plus 8703). Interprételo direccionalmente: una compilación igual o superior a la corregida es un fuerte indicador de que el host está parcheado, ya que la corrección UUID está en ese árbol. Una compilación por debajo de la corregida es no concluyente más que prueba de vulnerabilidad, porque hotfixes fuera de banda y backports pueden aplicar la corrección UUID sin aumentar el número de compilación; en ese caso, recurra a la verificación del formato del ticket a continuación.
Verifique el formato del ticket emitido si puede iniciar sesión. La cookie CUSTOM_SSO_TICKET no es HttpOnly, por lo que después de autenticarse puede leer su valor: un número de 13 dígitos significa vulnerable, un UUID significa parcheado. Esta es la verificación positiva más clara.
Actualice a la compilación corregida (o posterior) en cualquier host que sea vulnerable o que no pueda confirmar como parcheado. La corrección reemplaza el ticket predecible con un UUID aleatorio.
Busque intentos de explotación. En el host, serverOut_<fecha>.txt registra el throttling como ráfagas de:
IAMSecurityException ErrorCode: URL_ROLLING_THROTTLES_LIMIT_EXCEEDED,
RequestURI: "/showLogin.cc", RemoteAddr: <IP de origen>
Un pico de URL_ROLLING_THROTTLES_LIMIT_EXCEEDED en rutas de despacho de SSO/inicio de sesión desde una única IP de origen es un fuerte indicador de fuerza bruta de tickets. También revise los inicios de sesión exitosos recientes y la actividad de sesiones para detectar señales de toma de control.
Reduzca la exposición mientras tanto. Restrinja el acceso de red a la suite AD360 (no debería estar expuesta a internet), y si la ruta de reproducción no es necesaria, deshabilitar la integración CustomSSO elimina la precondición por completo.
Actualice el producto afectado al menos a la compilación corregida (ADSelfService Plus 6529, RecoveryManager Plus 6321, M365 Manager Plus 4817, ADAudit Plus 8703) o posterior. La corrección reemplaza el ticket SSO predecible System.currentTimeMillis() con UUID.randomUUID().
Este código se distribuye bajo una licencia MIT.
El uso de esta herramienta para atacar objetivos sin consentimiento mutuo previo es ilegal. Es responsabilidad del usuario final cumplir con todas las leyes locales, estatales y federales aplicables. Los desarrolladores no asumen ninguna responsabilidad y no son responsables por cualquier uso indebido o daño causado por este programa.