Hello there, ('ω')ノ
動画
1. タイトル
Lab: Exploiting path mapping for web cache deception — パス正規化の差異を突いた Web Cache Deception で API キーを奪取
2. 注意書き
重要:この手順は学習目的であり、ラボ以外の環境で絶対に実行しないでください。
3. 概要(この文書で何を学べるか)
このラボでは、オリジンサーバ(アプリ)とCDN/リバースプロキシのキャッシュが URL パスの解釈(正規化)を異なる規則で行うことを突く Web Cache Deception (WCD) を学びます。 ゴールは、被害者 carlos の /my-account レスポンス(API キーを含む)を 静的拡張子付きの偽パスでキャッシュさせ、攻撃者が同じ URL を後から閲覧して API キーを読むことです。
4. 必要な前提知識(短い箇条書き)
- パス正規化と正規表現ルーティング:アプリ側は
/my-account/abcを 抽象化して/my-accountとして扱うことがある。 - キャッシュの拡張子ベース規則:CDN は
.jsなど 静的拡張子が付くパスを キャッシュ対象にしがち。 - ヘッダ観察:
X-Cache: miss/hit、Cache-Control: max-age=...でキャッシュの有無・寿命を判断。
5. 攻撃(検証)方針(なぜその順序か)
- 自分のアカウントでログインし、/my-account のレスポンスに API キーがあることを確認 — 攻撃価値の確認。
- /my-account に余分なパスを付与しても内容が変わらない(オリジンが抽象化する)ことを確認 — ルーティングの手がかり。
- さらに静的拡張子(例
.js)を付けてキャッシュが有効になることを確認 —X-CacheとCache-Controlを観察。 - エクスプロイトサーバから被害者をその URL に誘導して「被害者の /my-account をその URL にキャッシュ」させる。
- キャッシュ寿命内に同じ URL を攻撃者が閲覧して被害者の API キーを取得。
6. ステップ別の概要(やること / 意図 / 期待される出力)
ステップ 1:ログインして API キーが露出することを確認
- やること:Burp の内蔵ブラウザで
wiener:peterでログイン。 - 意図:/my-account のレスポンス本文に 自分の API キーが含まれるのを確認(奪取対象があることを把握)。
- 期待:ページ中にキー(トークン文字列)が表示される。
ステップ 2:オリジンのパス抽象化を確認
- やること:Proxy → HTTP history から
GET /my-accountを Repeater に送り、パスを/my-account/abcに変更して送信。 - 意図:余分パスがあっても 同じアカウントページが返る=アプリは
/my-accountに 正規化している。 - 期待:レスポンス本文は同じく API キーを含む自分のアカウント情報。
ステップ 3:静的拡張子でキャッシュを有効化
やること:Repeater でパスを
/my-account/abc.jsに変更して送信。意図:キャッシュが 静的拡張子を見てエントリを作るか確認。
期待:
X-Cache: missとCache-Control: max-age=30(例)が付き、再送するとX-Cache: hitに変わる(同じ URL がキャッシュから配信される)。
ステップ 4:エクスプロイトで被害者を誘導(キャッシュ汚染)
- やること:Exploit server の Body に以下を配置(自分のラボ ID に置換・新しい任意セグメント名にする):
<script>
document.location="https://YOUR-LAB-ID.web-security-academy.net/my-account/wcd.js";
</script>
Deliver exploit to victim を実行。
意図:carlos が ログイン済みの状態で /my-account を
/my-account/wcd.jsとして取得 → オリジンは/my-accountに正規化して carlos のページを返す → キャッシュは/my-account/wcd.jsを静的資産として保存。期待:この時点で
/my-account/wcd.jsのキャッシュには carlos の API キーを含むレスポンスが保存される。
ステップ 5:攻撃者がキャッシュから carlos のキーを取得
- やること:30 秒以内(
max-age内)に
https://YOUR-LAB-ID.web-security-academy.net/my-account/wcd.js
へアクセス。
意図:キャッシュ済みの carlos のレスポンスを取得する。
期待:本文に carlos の API キーが含まれる。コピーして Submit solution で提出し、ラボクリア。
7. トラブルシューティング(成功しない場合のチェック)
- X-Cache が常に miss:拡張子が
.jsになっているか、同一の完全一致 URL を再送しているかを確認。TTL(例 30 秒)を過ぎていないか。 - 被害者のレスポンスが取れない:Exploit の 任意セグメント名を新規にして再送(以前の自分のキャッシュを参照している可能性)。
- ログイン状態の影響:carlos が閲覧したタイミングで その URL がキャッシュされることが重要。Exploit 配信後に確認を。
- キャッシュ寿命切れ:
Cache-Control: max-ageを超えたら再度誘導→即確認。
8. なぜこれが危険なのか(本質)
- パス解釈の不一致:オリジンは抽象化して動的ページを返す一方、キャッシュは拡張子で静的扱いして保存 → 動的・機密ページが静的 URL として第三者に配布される。
- セッション依存の機密情報の漏洩:個人の API キー・個人情報が 誰でもアクセス可能なキャッシュに載る。
9. 防御(実務で取るべき対策)
- キャッシュポリシーの厳格化:動的・認証必須のパスには常に
Cache-Control: no-store, privateを付与。 - パス正規化の一致:キャッシュ層とオリジンで同じ正規化規則(特に末尾スラッシュ、余分セグメント、拡張子)を適用。
- 拡張子ベースのキャッシュを制限:
/my-account/*のような動的領域では 拡張子有無に関係なく非キャッシュに。 - 認証コンテンツのキャッシュ禁止:Set-Cookie と同時に配信されるレスポンスに 強制 no-store。
- 監視・検出:不審なパス(
/dynamic/xxx.js等)での急なキャッシュヒット増加を検出。
10. 検証の確認ポイント(ラボでの成功条件)
/my-account/wcd.jsにアクセスして carlos の API キーが見える。- Submit solution でそのキーを提出し Solved が表示。
11. まとめ
オリジンは /my-account/abc(.js) を /my-account に抽象化 → キャッシュは .js を静的として保存 → 被害者でキャッシュを汚染 → 同 URL を攻撃者が閲覧して API キーを取得(ラボクリア)。
Best regards, (^^ゞ