Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-19490-check — Détecter en toute sécurité le contournement d'authentification SAML de Citrix NetScaler CVE-2026-19490 | Kitploit
Outils/GitHubGitHub/bishopfox/cve-2026-19490-check
Outils DéfensifsScanners de VulnérabilitésScanners de Vulnérabilités WebAnalyse des VulnérabilitésCollecte d'InformationsSécurité WebSécurité RéseauTests d'IntrusionAuthentification
GitHubbishopfox/cve-2026-19490-check

CVE-2026-19490-check

Détecter en toute sécurité le contournement d'authentification SAML de Citrix NetScaler CVE-2026-19490

1il y a 16h 34mPas encore vérifié
Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Contournement d'authentification par contexte nFactor SAML de Citrix NetScaler — Script de détection de vulnérabilité

Une vérification de vulnérabilité sûre et non authentifiée pour CVE-2026-19490, le contournement d'authentification pré-authentification dans le chemin du fournisseur de services SAML de Citrix NetScaler ADC / NetScaler Gateway (CTX696939, publié le 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). Signalé par Samarth Vashisht de l'équipe de tests d'intrusion de JPMorgan Chase.

L'appliance décode en base64 le paramètre RelayState d'une réponse SAML et, lorsque le texte en clair commence par ctx=, transmet le reste au désérialiseur de contexte nFactor. Sur une version non corrigée, un échec de désérialisation propage la longueur du RelayState décodé comme code de disposition interne de la requête au lieu d'une erreur, de sorte qu'un attaquant non authentifié choisit la branche interne que l'appliance emprunte ensuite uniquement en choisissant la longueur du RelayState. Certaines branches créent une véritable session Gateway ; d'autres font planter le moteur de paquets et redémarrent l'appliance. Ce script ne fait ni l'un ni l'autre — il envoie la seule longueur validée pour ne créer aucune session et ne pas toucher au moteur de paquets, et répond à une seule question par cible : Un résultat autre que n'est .

cette appliance est-elle vulnérable ?
VULNERABLE
pas en soi un certificat de bonne santé

Utilisation

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+, bibliothèque standard uniquement — aucun paquet tiers.

Pointez l'outil vers le serveur virtuel Gateway ou AAA, pas vers l'interface de gestion. L'exposition est propre à chaque serveur virtuel, donc une appliance comportant plusieurs VIP doit être testée pour chacune. La sonde porte une enveloppe de sécurité stricte — une seule longueur de RelayState validée, jamais balayée — que Est-il sûr de l'exécuter ? expose.

Options

OptionDescription
TARGETUne ou plusieurs cibles [https://]HOST[:PORT] ; le schéma par défaut est https://
-f, --targets-file FILELire les cibles depuis un fichier (une par ligne ; commentaires #)
--timeout SECSDélai d'attente par requête (par défaut : 15)
--workers NCibles simultanées (par défaut : 16) ; la sortie reste dans l'ordre d'entrée
-b, --briefUne seule ligne alignée par cible — idéal pour scanner de nombreux hôtes
--jsonÉmettre du JSON structuré, incluant chaque requête envoyée par cible
--no-colorDésactiver la sortie colorée (respecte aussi NO_COLOR et les non-TTY)

Exemples

Une appliance vulnérable (la sortie par défaut sur deux lignes). Le marqueur [!] et VULNERABLE s'affichent en rouge sur un 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

Une appliance corrigée :

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)

Le garde-fou anti-faux-positif qui se déclenche. La sonde et le contrôle de même longueur ont tous deux renvoyé le signal non corrigé, donc la réponse ne dépend pas de ce qui a été envoyé et la réponse d'apparence décisive est retirée :

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

Balayage d'un parc (--brief). Les deux lignes gateway.example.com sont les serveurs virtuels SP et IdP-only sur la même appliance — les deux répondent, ce qu'une vérification de précondition de configuration ne parviendrait pas à faire :

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

Sortie lisible par machine (--json). Chaque requête est incluse, de sorte qu'une conclusion peut être redérivée à partir des preuves plutôt que d'être crue sur parole. Le contrôle est enregistré par sa relation à la sonde plutôt que comme un verdict qui lui est propre, car un contrôle qui se lit comme une version corrigée est le résultat attendu sur toutes les versions :

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"
      }
    ]
  }
]

Est-il sûr de l'exécuter ?

Oui. Il est conçu pour un usage en production et en évaluation :

  • Une longueur fixe, jamais un balayage. Le RelayState de la sonde se décode en exactement 20 octets et l'outil n'envoie aucune autre longueur sous aucun drapeau. Sur une appliance non corrigée, la longueur décodée est le sélecteur de branche, et les branches incluent celles qui créent une session et celles qui provoquent un SIGSEGV du moteur de paquets — redémarrant tout le NetScaler et interrompant le trafic pendant environ 45 secondes. Vingt octets aboutissent à une branche d'erreur interne propre qui ne crée aucune session, et le constructeur de charge utile refuse de construire toute autre longueur, de sorte qu'une modification ailleurs ne peut pas élargir discrètement la sonde.
  • Validé par mesure. La sonde de 20 octets a été exécutée 10 fois consécutivement contre une version non corrigée 13.1-63.18 sans aucun core généré et sans redémarrage du moteur de paquets. La vérification elle-même a depuis été exécutée contre les deux branches de maintenance, des deux côtés du correctif, et contre des serveurs virtuels fournisseur de services et IdP-only, sans redémarrage du moteur de paquets sur aucun d'entre eux.
  • Aucune authentification, aucun matériel d'identification, aucun changement d'état. Aucune assertion, signature, horodatage, session ou certificat client n'est présenté nulle part dans cette vérification. Le paramètre SAMLResponse doit être présent pour que la branche RelayState soit atteinte, mais son contenu est sans importance, donc ce sont quatre octets de remplissage. La branche n'émet aucun cookie et n'écrit aucune configuration.
  • Garde-fou anti-faux-positif. VULNERABLE n'est jamais signalé sur une seule réponse — voir le contrôle.

Si vous modifiez la sonde, ne changez pas la longueur du RelayState décodé et ne balayez pas les longueurs. Vingt octets sont porteurs, et plus court n'est pas plus sûr. D'autres longueurs sont au mieux non testées et au pire une panne d'appliance.

Empreinte des requêtes et des journaux

Trois requêtes HTTP par cible, et une quatrième uniquement lorsque l'appliance renvoie le signal non corrigé :

#RequêteObjectif
1GET /logon/LogonPoint/tmindex.htmlIdentification NetScaler (jetons Content-Security-Policy)
2GET /vpn/js/rdx/core/rdx.jsIdentification NetScaler
3POST /cgi/samlauthla sonde
4POST /cgi/samlauthle contrôle, envoyé uniquement après un signal non corrigé

Les redirections ne sont pas suivies et aucun cookie n'est jamais renvoyé — NetScaler sert un NSC_DLGE expiré qu'un client rejouant la requête transporterait dans la requête 4, transformant le POST en page de connexion.

nsppe journalise le POST SAML dans /var/log/ns.log au niveau informationnel, sans nécessiter de commutateur de débogage, comme un échec de désérialisation de contexte nFactor incluant la ligne nFactor: ctx deserialize aaa_info, base64 decode failed. Il n'y a aucune ligne de création de session ou de connexion à cette longueur, ce qui distingue un scan d'une tentative de contournement.

Comment ça fonctionne

Le correctif est une seule instruction. Lors d'une désérialisation de contexte échouée, la version vulnérable reporte la longueur du RelayState décodé comme statut de la requête ; la version corrigée reporte l'erreur constante 0xe0005, rendue comme Malformed Assertion. Ainsi un seul POST les sépare :

Réponse à la sondeVersionVerdict
500 Internal Server Error 43524non corrigéeVULNERABLE
200 Malformed Assertion sent to NetscalercorrigéePATCHED

La version corrigée répond Malformed Assertion à toutes les longueurs, ce qui fait de la réponse non corrigée un oracle plutôt qu'une coïncidence.

Le contrôle est ce qui donne un sens à un 500

VULNERABLE repose sur une seule réponse distinctive, donc l'outil vérifie que la réponse dépend réellement de ce qui a été envoyé. Après le signal non corrigé, il répète la requête avec un RelayState de contrôle de la même longueur décodée de 20 octets, ne différant que par les 16 octets après ctx=. Ce contenu est rejeté par un garde en amont du désérialiseur, donc toutes les versions testées — corrigées et non corrigées — y répondent 200 Malformed Assertion. Le verdict ne tient que si les deux réponses diffèrent. Si elles correspondent, quelque chose renvoie 500/43524 indépendamment de l'entrée, et le résultat est INCONCLUSIVE étiqueté flat-response plutôt qu'un faux VULNERABLE. Maintenir le contrôle à la même longueur décodée le garde à l'intérieur de l'enveloppe de sécurité validée et isole le contenu comme seule variable.

Le garde est unidirectionnel. Il ne peut pas valider un verdict PATCHED, car une appliance véritablement corrigée répond de manière identique à la sonde et au contrôle — c'est ce que signifie être corrigé ici. Voir Limitations.

Il répond aussi sur les serveurs virtuels IdP-only

La désérialisation de RelayState s'exécute avant la correspondance de politique SAML, donc un serveur virtuel ne portant qu'un samlIdPPolicy répond à la sonde, pas seulement celui avec un samlAction de fournisseur de services lié. C'est une couverture plus large qu'une vérification de précondition de configuration ne peut offrir.

Un non-résultat n'est jamais une affirmation de sécurité

La réponse vulnérable est la seule auto-corroborante : elle porte un marqueur spécifique, et le contrôle prouve que la réponse dépend de ce qui a été envoyé. PATCHED est aussi une preuve positive — l'erreur corrigée de l'appliance elle-même sur le chemin atteint par la sonde — mais elle est limitée à ce CVE et à ce chemin. INCONCLUSIVE et ERROR ne sont pas du tout des preuves : la sonde n'a jamais atteint le désérialiseur, donc l'état du correctif est inconnu, et c'est pourquoi INCONCLUSIVE est un verdict distinct plutôt que fusionné dans PATCHED. Rapporter le silence comme une réussite se trompe dans la direction dangereuse. Là où vous avez besoin de certitude, confirmez avec show ns version par rapport aux versions dans Remédiation.

Verdicts

Chaque verdict porte une courte étiquette reason. --brief l'affiche comme troisième colonne et --json la porte comme reason.

VerdictÉtiquette reasonSignification
VULNERABLEinternal-error-43524L'appliance a propagé la longueur du RelayState décodé comme son erreur interne, et un contrôle de même longueur a prouvé que la réponse dépend de ce qui a été envoyé. Le correctif CTX696939 est absent — corrigez-la.
PATCHEDfixed-error-returnedL'appliance a renvoyé l'erreur corrigée sur le chemin atteint par la sonde. Limité à ce CVE, et voir Limitations sur les dispositifs interposés.
UNAFFECTEDno-saml-endpoint/cgi/samlauth a renvoyé 404, donc le consommateur d'assertion SAML n'est pas servi ici. Par vserver, pas par appliance, et voir la mise en garde sur les versions plus anciennes dans Limitations.
INCONCLUSIVEflat-responseLa sonde et le contrôle de même longueur ont répondu de manière identique, donc la réponse ne dépend pas de ce qui a été envoyé. Le garde-fou anti-faux-positif se déclenche.
INCONCLUSIVEgeneric-internal-errorLe point de terminaison a renvoyé 43549, son erreur interne générique, que les versions corrigées et non corrigées renvoient. Ce n'est pas le discriminant — et notez que c'est bien le marqueur non corrigé pour le CVE-2026-8452 sans rapport, donc cela ressemble à une détection et n'en est pas une.
INCONCLUSIVEunrecognized-replyLe point de terminaison a répondu avec quelque chose hors de l'ensemble reconnu.
INCONCLUSIVEno-probe-responseL'hôte a répondu à l'identification mais pas à la sonde — un délai d'attente, une réinitialisation, ou un middlebox qui abandonne le POST. Réessayez.
ERRORnot-identifiedNon identifié comme un NetScaler, ou injoignable.

Les quatre raisons INCONCLUSIVE signifient la même chose pour la prise de décision — inconnu, pas corrigé. L'étiquette nomme la condition à corriger avant de relancer.

Codes de sortie

CodeSignification
0Aucune cible n'était VULNERABLE
1Au moins une cible est VULNERABLE
2Erreur d'utilisation (arguments invalides / fichier de cibles illisible)

Le code de sortie 0 n'est pas un certificat de bonne santé. PATCHED, UNAFFECTED et les quatre raisons INCONCLUSIVE s'y fondent, et une seule d'entre elles est un résultat positif. Un wrapper qui doit distinguer « corrigé » de « impossible à classer » doit lire le verdict — première colonne de --brief, ou le champ verdict de --json — et non le code de sortie.

Limitations

  • Un WAF ou un équilibreur de charge peut fausser un verdict PATCHED. Malformed Assertion est ce que l'appliance renvoie chaque fois que la sonde n'atteint pas le désérialiseur de contexte, et être corrigée n'est qu'une des raisons pour lesquelles cela se produit. Un dispositif interposé qui supprime, altère ou court-circuite le paramètre RelayState produit donc PATCHED sur une appliance vulnérable, et aucune requête supplémentaire que l'outil pourrait envoyer ne séparerait les deux. Là où quelque chose peut se trouver devant l'appliance, confirmez avec show ns version.
  • UNAFFECTED est limité aux versions actuelles. Sur 14.1-43.55 / 13.1-61.27 et antérieures, l'avis indique que l'exposition ne nécessite pas du tout d'action SAML — tout serveur virtuel Gateway ou AAA est affecté — donc un 404 sur une telle version ne met pas l'appliance hors de portée. Ce point est tiré de l'avis plutôt que mesuré.
  • Ceci vérifie un seul CVE, pas le niveau de correctif de l'appliance. PATCHED ne dit rien sur aucune autre vulnérabilité NetScaler, y compris CVE-2026-19489 dans le même bulletin.
  • Ce n'est pas une vérification d'exploitation, ni une vérification de compromission. VULNERABLE établit que le correctif est absent sur le chemin atteint par la sonde. Cela ne mesure pas jusqu'où un attaquant pourrait pousser le contournement sur votre configuration, et cela ne vous dira pas si quelqu'un l'a déjà fait — traquez cela séparément dans /var/log/ns.log.
  • Il ne peut pas vous dire si les branches de déni de service sont atteignables. L'outil envoie une seule longueur validée et n'explore jamais les autres, par conception.
  • Atteignabilité. Un résultat reflète ce que l'appliance expose à la position réseau depuis laquelle vous l'exécutez.

Remédiation

Mettez à niveau vers 13.1-63.21 ou ultérieure, ou 14.1-73.32 ou ultérieure (FIPS et NDcPP : 13.1-37.277 pour 13.1-FIPS et 13.1-NDcPP, 14.1-73.32 FIPS pour 14.1-FIPS), selon CTX696939. Les appliances sur 12.1 ou 13.0 n'ont pas de correctif et n'en recevront pas — ces branches sont en fin de vie et devraient être migrées vers une branche prise en charge.

Trois notes supplémentaires :

  • Corrigez les deux nœuds d'une paire HA. Un secondaire non corrigé est une appliance pleinement exposée dès qu'il prend le relais.
  • Si vous ne pouvez pas corriger aujourd'hui, vérifiez le seul commutateur global qui borne l'impact. La session que ce bug crée sur un serveur virtuel Gateway ignore l'évaluation de politique de session, donc elle ne reprend pas le defaultAuthorizationAction d'un vpn sessionAction lié au vserver — elle retombe sur le set vpn parameter -defaultAuthorizationAction global. La valeur par défaut livrée est DENY ; ALLOW est courant sur le terrain car c'est ce vers quoi les administrateurs se tournent au lieu d'écrire des politiques d'autorisation par utilisateur, et ALLOW est ce qui permet à la session non authentifiée d'atteindre les ressources internes. C'est global, pas par vserver. Cela borne l'impact ; ce n'est pas un correctif.
  • Délimitez votre inventaire par configuration SAML, pas par type de serveur virtuel. Vérifiez la configuration en cours d'exécution pour add authentication samlAction et add authentication samlIdPProfile aux côtés de add authentication vserver et add vpn vserver — sous réserve de la mise en garde sur les versions plus anciennes ci-dessus.

CTX696939 corrige aussi CVE-2026-19489, et cette surface chevauche fortement CVE-2026-8452 du bulletin précédent : sur les versions à partir de 14.1-43.56 / 13.1-61.28, les deux problèmes sont conditionnés à une action SAML configurée, donc un seul audit de configuration délimite les deux.

Licence

Ce code est distribué sous une licence MIT.

Avertissement juridique

L'utilisation de cet outil pour attaquer des cibles sans consentement mutuel préalable est illégale. Il est de la responsabilité de l'utilisateur final de respecter toutes les lois locales, étatiques et fédérales applicables. Les développeurs n'assument aucune responsabilité et ne sont pas responsables de tout usage abusif ou dommage causé par ce programme.

Voir aussi

  • Citrix CTX696939 — bulletin de sécurité NetScaler
  • NVD — CVE-2026-19490
  • NVD — CVE-2026-19489
  • NVD — CVE-2026-8452
Télécharger l’outil