Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-19490-check — Detecta de forma segura el bypass de autenticación SAML de Citrix NetScaler CVE-2026-19490 | Kitploit
Herramientas/GitHubGitHub/bishopfox/cve-2026-19490-check
Herramientas DefensivasEscáneres de VulnerabilidadesEscáneres de Vulnerabilidades WebAnálisis de VulnerabilidadesRecopilación de InformaciónSeguridad WebSeguridad de RedesPruebas de PenetraciónAutenticación
GitHubbishopfox/cve-2026-19490-check

CVE-2026-19490-check

Detecta de forma segura el bypass de autenticación SAML de Citrix NetScaler CVE-2026-19490

hace 15h 42mAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Ver Repositorio
Compartir

Citrix NetScaler SAML nFactor Context Authentication Bypass — Script de detección de vulnerabilidades

Una comprobación de vulnerabilidad segura y no autenticada para CVE-2026-19490, el bypass de autenticación previo a la autenticación en la ruta del proveedor de servicios SAML de Citrix NetScaler ADC / NetScaler Gateway (CTX696939, publicado el 2026-08-19). CWE-288, CVSS v4.0 9.3 (AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:L/SI:L/SA:L). Reportado por Samarth Vashisht del equipo de pruebas de penetración de JPMorgan Chase.

El dispositivo decodifica en base64 el parámetro RelayState de una respuesta SAML y, cuando el texto plano comienza con ctx=, entrega el resto al deserializador de contexto nFactor. En una compilación sin parchear, un fallo de deserialización propaga la longitud del RelayState decodificado como el código de disposición interno de la solicitud en lugar de un error, por lo que un atacante no autenticado elige qué rama interna toma el dispositivo a continuación simplemente eligiendo la longitud del RelayState. Algunas ramas generan una sesión real de Gateway; otras provocan un fallo del motor de paquetes y reinician el dispositivo. Este script no hace ninguna de las dos cosas — envía la única longitud validada que no crea ninguna sesión y deja en paz al motor de paquetes, y responde a una única pregunta por objetivo: Un resultado distinto de .

¿es vulnerable este dispositivo?
VULNERABLE
no es por sí mismo un certificado de buena salud

Uso

root@kitploit:~
# single target
./cve_2026_19490_check.py https://gateway.example.com

# a specific Gateway or AAA virtual server
./cve_2026_19490_check.py https://gateway.example.com:9443

# several targets; the scheme defaults to https://
./cve_2026_19490_check.py gw-a.example.com gw-b.example.com:9443

# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_19490_check.py -f targets.txt --brief

# machine-readable output for pipelines
./cve_2026_19490_check.py -f targets.txt --json > results.json

Python 3.8+, solo biblioteca estándar — sin paquetes de terceros.

Apunte la herramienta al servidor virtual Gateway o AAA, no a la interfaz de gestión. La exposición es por servidor virtual, por lo que un dispositivo con varias VIP necesita que se pruebe cada una. La sonda lleva un estricto envoltorio de seguridad — una única longitud de RelayState validada, nunca un barrido — que ¿Es seguro ejecutarlo? detalla.

Opciones

FlagDescripción
TARGETUno o más objetivos [https://]HOST[:PORT]; el esquema por defecto es https://
-f, --targets-file FILELeer objetivos desde un archivo (uno por línea; comentarios con #)
--timeout SECSTiempo de espera por solicitud (por defecto: 15)
--workers NObjetivos concurrentes (por defecto: 16); la salida mantiene el orden de entrada
-b, --briefUna sola línea alineada por objetivo — ideal para escanear muchos hosts
--jsonEmitir JSON estructurado, incluyendo cada solicitud enviada por objetivo
--no-colorDeshabilitar la salida con color (también respeta NO_COLOR y entornos no TTY)

Ejemplos

Un dispositivo vulnerable (la salida predeterminada de dos líneas). El marcador [!] y VULNERABLE se muestran en rojo en una TTY:

root@kitploit:~
$ ./cve_2026_19490_check.py https://gateway.example.com:9443
[!] https://gateway.example.com:9443: VULNERABLE  [internal-error-43524]
      HTTP 500 / 43524: the decoded RelayState length was propagated as the internal error, so the CTX696939 fix is absent

Un dispositivo parcheado:

root@kitploit:~
$ ./cve_2026_19490_check.py https://vpn.example.com
[+] https://vpn.example.com: PATCHED  [fixed-error-returned]
      HTTP 200 "Malformed Assertion": the fixed error was returned on the path this probe reached, so the CTX696939 fix is present (>= 13.1-63.21 / 14.1-73.32)

La activación de la protección contra falsos positivos. Tanto la sonda como el control de la misma longitud devolvieron la señal sin parchear, por lo que la respuesta no depende de lo que se envió y se retira la respuesta que parecía decisiva:

root@kitploit:~
$ ./cve_2026_19490_check.py https://sp-strict.example.com
[?] https://sp-strict.example.com: INCONCLUSIVE  [flat-response]
      the probe and the same-length control both answered HTTP 500 / 43524, so the reply does not depend on what was sent and the fix was never exercised; unknown, not patched

Barriendo un parque (--brief). Las dos filas de gateway.example.com son los servidores virtuales SP y solo-IdP en el mismo dispositivo — ambos responden, algo que una comprobación de precondición de configuración no lograría:

root@kitploit:~
$ ./cve_2026_19490_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE    https://gateway.example.com:9443         internal-error-43524
VULNERABLE    https://gateway.example.com:9444         internal-error-43524
PATCHED       https://vpn.example.com                  fixed-error-returned
INCONCLUSIVE  https://sp-strict.example.com            flat-response
UNAFFECTED    https://lb.example.com                   no-saml-endpoint
ERROR         https://www.example.com                  not-identified
exit: 1

Salida legible por máquina (--json). Se incluye cada solicitud, por lo que un hallazgo puede volver a derivarse de la evidencia en lugar de confiar en él. El control se registra por su relación con la sonda en lugar de como un veredicto propio, porque un control que se lee como una compilación parcheada es el resultado esperado en todas las compilaciones:

root@kitploit:~
$ ./cve_2026_19490_check.py https://gateway.example.com:9443 --json
[
  {
    "target": "https://gateway.example.com:9443",
    "verdict": "VULNERABLE",
    "reason": "internal-error-43524",
    "detail": "HTTP 500 / 43524: the decoded RelayState length was propagated as the internal error, so the CTX696939 fix is absent",
    "netscaler_indicators": [
      "CSP contains citrixng://",
      "CSP contains com.citrix.nsgclient://",
      "CSP contains nsgcepa://",
      "CSP report-uri /nscsp_violation/report_uri",
      "/vpn/js/rdx/ present (HTTP 404)"
    ],
    "attempts": [
      {
        "kind": "probe",
        "path": "/cgi/samlauth",
        "status": 500,
        "state": "unpatched",
        "detail": "HTTP 500 / 43524: the decoded RelayState length was propagated as the internal error"
      },
      {
        "kind": "control",
        "path": "/cgi/samlauth",
        "status": 200,
        "state": "differs-from-probe",
        "detail": "same-length control: HTTP 200 \"Malformed Assertion\": the fixed error was returned"
      }
    ]
  }
]

¿Es seguro ejecutarlo?

Sí. Está diseñado para uso en producción y evaluación:

  • Una longitud fija, nunca un barrido. El RelayState de la sonda se decodifica a exactamente 20 bytes y la herramienta no envía ninguna otra longitud bajo ningún flag. En un dispositivo sin parchear, la longitud decodificada es el selector de rama, y las ramas incluyen algunas que crean una sesión y otras que provocan un SIGSEGV en el motor de paquetes — reiniciando todo el NetScaler y descartando el tráfico durante aproximadamente 45 segundos. Veinte bytes aterrizan en una rama limpia de error interno que no crea ninguna sesión, y el constructor de payload se niega a construir cualquier otra longitud, por lo que una edición en otro lugar no puede ampliar silenciosamente la sonda.
  • Validado por medición. La sonda de 20 bytes se ejecutó 10 veces consecutivas contra un 13.1-63.18 sin parchear con cero cores generados y sin reinicio del motor de paquetes. La comprobación en sí se ha ejecutado desde entonces contra ambas ramas de mantenimiento, en ambos lados del parche, y contra servidores virtuales de proveedor de servicios y solo-IdP por igual, sin reinicio del motor de paquetes en ninguno de ellos.
  • Sin autenticación, sin material de credenciales, sin cambio de estado. No se presenta ninguna aserción, firma, marca de tiempo, sesión ni certificado de cliente en ningún lugar de esta comprobación. El parámetro SAMLResponse debe estar presente para que se alcance la rama RelayState, pero su contenido es irrelevante, por lo que son cuatro bytes de basura. La rama no emite ninguna cookie ni escribe ninguna configuración.
  • Protección contra falsos positivos. VULNERABLE nunca se reporta con una sola respuesta — véase el control.

Si modifica la sonda, no cambie la longitud del RelayState decodificado y no barra longitudes. Veinte bytes es fundamental, y más corto no es más seguro. Otras longitudes no están probadas en el mejor de los casos y son una interrupción del dispositivo en el peor.

Huella de solicitudes y registros

Tres solicitudes HTTP por objetivo, y una cuarta solo cuando el dispositivo devuelve la señal sin parchear:

#SolicitudPropósito
1GET /logon/LogonPoint/tmindex.htmlIdentificación de NetScaler (tokens de Content-Security-Policy)
2GET /vpn/js/rdx/core/rdx.jsIdentificación de NetScaler
3POST /cgi/samlauthla sonda
4POST /cgi/samlauthel control, enviado solo tras una señal sin parchear

No se siguen las redirecciones y nunca se devuelve ninguna cookie — NetScaler sirve un NSC_DLGE caducado que un cliente que lo reenvía llevaría a la solicitud 4, convirtiendo el POST en una página de inicio de sesión.

nsppe registra el POST SAML en /var/log/ns.log a nivel informativo, sin necesidad de ningún interruptor de depuración, como un fallo de deserialización de contexto nFactor que incluye la línea nFactor: ctx deserialize aaa_info, base64 decode failed. No hay líneas de creación de sesión o de inicio de sesión con esta longitud, que es lo que distingue un escaneo de un intento del bypass.

Cómo funciona

El parche es una sola instrucción. Ante una deserialización de contexto fallida, la compilación vulnerable lleva la longitud del RelayState decodificado hacia adelante como el estado de la solicitud; la compilación corregida lleva el error constante 0xe0005, representado como Malformed Assertion. Así que un solo POST los separa:

Respuesta a la sondaCompilaciónVeredicto
500 Internal Server Error 43524sin parchearVULNERABLE
200 Malformed Assertion sent to NetscalerparcheadaPATCHED

La compilación parcheada responde Malformed Assertion a cualquier longitud, que es lo que hace que la respuesta sin parchear sea un oráculo en lugar de una coincidencia.

El control es lo que hace que un 500 signifique algo

VULNERABLE se basa en una única respuesta distintiva, por lo que la herramienta verifica que la respuesta realmente depende de lo que se envió. Tras la señal sin parchear, repite la solicitud con un RelayState de control de la misma longitud decodificada de 20 bytes, que difiere solo en los 16 bytes posteriores a ctx=. Ese contenido es rechazado por una guarda anterior al deserializador, por lo que todas las compilaciones probadas — parcheadas y sin parchear — lo responden con 200 Malformed Assertion. El veredicto se mantiene solo si las dos respuestas difieren. Si coinciden, algo está devolviendo 500/43524 independientemente de la entrada, y el resultado es INCONCLUSIVE etiquetado como flat-response en lugar de un falso VULNERABLE. Mantener el control en la misma longitud decodificada lo mantiene dentro del envoltorio de seguridad validado y aísla el contenido como la única variable.

La guarda es unidireccional. No puede validar un veredicto PATCHED, porque un dispositivo genuinamente parcheado responde de forma idéntica a la sonda y al control — eso es lo que significa estar parcheado aquí. Véase Limitaciones.

También responde en servidores virtuales solo-IdP

La deserialización de RelayState se ejecuta antes de la coincidencia de políticas SAML, por lo que un servidor virtual que lleva solo un samlIdPPolicy responde a la sonda, no solo uno con un samlAction de proveedor de servicios vinculado. Eso es una cobertura más amplia que la que puede ofrecer una comprobación de precondición de configuración.

Una no-coincidencia nunca es una afirmación de seguridad

La respuesta vulnerable es la única que se corrobora a sí misma: lleva un marcador específico, y el control demuestra que la respuesta depende de lo que se envió. PATCHED también es evidencia positiva — el propio error corregido del dispositivo en la ruta que alcanzó la sonda — pero está acotado a este CVE y a esa ruta. INCONCLUSIVE y ERROR no son evidencia en absoluto: la sonda nunca alcanzó el deserializador, por lo que el estado del parche es desconocido, y por eso INCONCLUSIVE es un veredicto separado en lugar de fusionarse con PATCHED. Reportar el silencio como aprobado se equivoca en la dirección peligrosa. Donde necesite certeza, confirme con show ns version contra las compilaciones en Remediación.

Veredictos

Cada veredicto lleva una etiqueta reason corta. --brief la imprime como la tercera columna y --json la lleva como reason.

VeredictoEtiqueta de motivoSignificado
VULNERABLEinternal-error-43524El dispositivo propagó la longitud del RelayState decodificado como su error interno, y un control de la misma longitud demostró que la respuesta depende de lo que se envió. El parche CTX696939 está ausente — parchee.
PATCHEDfixed-error-returnedEl dispositivo devolvió el error corregido en la ruta que alcanzó la sonda. Acotado a este CVE, y véase Limitaciones sobre dispositivos interpuestos.
UNAFFECTEDno-saml-endpoint/cgi/samlauth devolvió 404, por lo que el consumidor de aserciones SAML no se sirve aquí. Por vserver, no por dispositivo, y véase la advertencia sobre compilaciones antiguas en Limitaciones.
INCONCLUSIVEflat-responseLa sonda y el control de la misma longitud respondieron de forma idéntica, por lo que la respuesta no depende de lo que se envió. La protección contra falsos positivos se activó.
INCONCLUSIVEgeneric-internal-errorEl endpoint devolvió 43549, su error interno genérico, que devuelven tanto las compilaciones parcheadas como las sin parchear. No es el discriminador — y tenga en cuenta que sí es el marcador sin parchear del CVE-2026-8452 no relacionado, por lo que parece un acierto y no lo es.
INCONCLUSIVEunrecognized-replyEl endpoint respondió con algo fuera del conjunto reconocido.
INCONCLUSIVEno-probe-responseEl host respondió a la identificación pero no a la sonda — un tiempo de espera, un reinicio, o un middlebox descartando el POST. Reintente.
ERRORnot-identifiedNo identificado como un NetScaler, o inalcanzable.

Los cuatro motivos de INCONCLUSIVE significan lo mismo para la toma de decisiones — desconocido, no parcheado. La etiqueta nombra qué condición corregir antes de volver a ejecutar.

Códigos de salida

CódigoSignificado
0Ningún objetivo era VULNERABLE
1Al menos un objetivo es VULNERABLE
2Error de uso (argumentos incorrectos / archivo de objetivos ilegible)

La salida 0 no es un certificado de buena salud. PATCHED, UNAFFECTED y los cuatro motivos de INCONCLUSIVE se reducen a ella, y solo uno de esos es un resultado positivo. Un wrapper que necesite distinguir "parcheado" de "no se pudo clasificar" debe leer el veredicto — primera columna de --brief, o el campo verdict de --json — no el código de salida.

Limitaciones

  • Un WAF o balanceador de carga puede sesgar un veredicto PATCHED. Malformed Assertion es lo que el dispositivo devuelve siempre que la sonda no logra alcanzar el deserializador de contexto, y estar parcheado es solo una de las razones por las que eso ocurre. Un dispositivo interpuesto que elimina, altera o cortocircuita el parámetro RelayState produce por tanto PATCHED en un dispositivo vulnerable, y ninguna solicitud adicional que la herramienta pudiera enviar separaría las dos. Donde algo pueda estar delante del dispositivo, confirme con show ns version.
  • UNAFFECTED está acotado a las compilaciones actuales. En 14.1-43.55 / 13.1-61.27 y anteriores, el aviso indica que la exposición no requiere ninguna acción SAML en absoluto — cualquier servidor virtual Gateway o AAA está afectado — por lo que un 404 en tal compilación no deja al dispositivo fuera del alcance. Ese tramo se toma del aviso en lugar de medirse.
  • Esto comprueba un CVE, no el nivel de parche del dispositivo. PATCHED no dice nada sobre ninguna otra vulnerabilidad de NetScaler, incluido CVE-2026-19489 en el mismo boletín.
  • No es una comprobación de explotación, ni una comprobación de compromiso. VULNERABLE establece que el parche está ausente en la ruta que alcanzó la sonda. No mide hasta dónde podría llevar un atacante el bypass en su configuración, y no le dirá si alguien ya lo ha hecho — búsquelo en /var/log/ns.log por separado.
  • No puede decirle si las ramas de denegación de servicio son alcanzables. La herramienta envía una longitud validada y nunca explora las demás, por diseño.
  • Alcanzabilidad. Un resultado refleja lo que el dispositivo expone a la posición de red desde la que lo ejecuta.

Remediación

Actualice a 13.1-63.21 o posterior, o 14.1-73.32 o posterior (FIPS y NDcPP: 13.1-37.277 para 13.1-FIPS y 13.1-NDcPP, 14.1-73.32 FIPS para 14.1-FIPS), según CTX696939. Los dispositivos en 12.1 o 13.0 no tienen parche y no recibirán ninguno — esas ramas están al final de su vida útil y deben migrarse a una rama soportada.

Tres notas adicionales:

  • Parchee ambos nodos de un par HA. Un secundario sin parchear es un dispositivo totalmente expuesto en el momento en que toma el control.
  • Si no puede parchear hoy, compruebe el único interruptor global que acota el impacto. La sesión que este bug genera en un servidor virtual Gateway omite la evaluación de la política de sesión, por lo que no recoge el defaultAuthorizationAction de ningún vpn sessionAction vinculado al vserver — recurre al set vpn parameter -defaultAuthorizationAction global. El valor predeterminado de fábrica es DENY; ALLOW es común en el campo porque es a lo que recurren los administradores en lugar de escribir políticas de autorización por usuario, y ALLOW es lo que permite que la sesión no autenticada alcance recursos internos. Es global, no por vserver. Esto acota el impacto; no es un parche.
  • Delimite su inventario por configuración SAML, no por tipo de servidor virtual. Compruebe la configuración en ejecución en busca de add authentication samlAction y add authentication samlIdPProfile junto con add authentication vserver y add vpn vserver — sujeto a la advertencia sobre compilaciones antiguas anterior.

CTX696939 también corrige CVE-2026-19489, y esta superficie se solapa en gran medida con CVE-2026-8452 del boletín anterior: en compilaciones desde 14.1-43.56 / 13.1-61.28 en adelante, ambos problemas están condicionados a una acción SAML configurada, por lo que una auditoría de configuración delimita ambos.

Licencia

Este código se distribuye bajo una licencia MIT.

Aviso legal

El uso de esta herramienta para atacar objetivos sin consentimiento mutuo previo es ilegal. Es responsabilidad del usuario final obedecer todas las leyes locales, estatales y federales aplicables. Los desarrolladores no asumen ninguna responsabilidad y no son responsables de ningún mal uso o daño causado por este programa.

Véase también

  • Citrix CTX696939 — Boletín de seguridad de NetScaler
  • NVD — CVE-2026-19490
  • NVD — CVE-2026-19489
  • NVD — CVE-2026-8452
Descargar herramienta