Lab: Exploiting path delimiters for web cache deception — 解説と手順(PRACTITIONER・アウトライン統一版)
動画
1. タイトル
Lab: Exploiting path delimiters for web cache deception — パス区切り文字の解釈差異を突いて API キーを奪取
2. 注意書き
重要:学習目的のみ。ラボ以外での実施は禁止。
3. 概要
このラボは、オリジンサーバとキャッシュ(CDN/リバースプロキシ)が URL の“区切り文字(delimiter)” を 異なる規則で解釈することを突く Web Cache Deception (WCD) の実践です。
目標は、carlos の /my-account のレスポンス(API キーを含む)を、区切り文字+静的拡張子(例 .js)を使った偽パスでキャッシュさせ、同じ URL を攻撃者があとで開いて API キーを読むことです。
4. 必要な前提知識(短い箇条書き)
- パス区切りの解釈差:
?や;など、どこで“パスが終わるか”の判定がキャッシュとオリジンで異なる場合がある。 - 静的ディレクトリ/拡張子ベースのキャッシュ規則:
.js,.cssなどはキャッシュ対象になりやすい。 - ヘッダ観察:
X-Cache: miss/hit、Cache-Control: max-age=...の読み方。
5. 攻撃(検証)方針(なぜその順序か)
- /my-account に API キーが露出していることを自分のアカウントで確認。
- オリジンが何を“区切り”として扱うかを系統的に特定(Intruder で候補文字を一斉試験)。
- キャッシュ側の解釈とオリジンの解釈の不一致を見つける(静的拡張子付きで
X-Cacheの挙動を見る)。 - 区切り不一致+
.jsを使った悪性 URL を作成し、carlos を誘導して彼のレスポンスをキャッシュ。 - 同じ URL を攻撃者が開いて API キーを取得。
6. ステップ別の概要(やること / 意図 / 期待される出力)
ステップ 1:ログインして API キー露出を確認
- やること:Burp のブラウザで
wiener:peterでログイン。 - 意図:
/my-accountのレスポンスに 自分の API キーが含まれることを確認(奪取対象の価値)。 - 期待:本文に自分の API キーが表示。
ステップ 2:オリジンが使う“区切り文字”を同定(Intruder)
- Proxy → HTTP history で
GET /my-accountを Repeater に送る。 - Repeater で
/my-account/abcに変更 → 404(抽象化しない)を確認。 /my-accountabc(区切り無しの連結)も 404。これを“基準”にする。- リクエストを Intruder に送る。Sniper を選び、
/my-account§§abcの位置に候補文字を差し込み。 - Payloads に delimiter 候補のリスト(例:`; ? # , %2F %2e などラボ付与のリスト**)を登録し、URL-encode these charactersはオフ。
Start attack → Status code でソート。
- 観察:
;と?が 200(自分の API キー含む)、他は 404 → オリジンは;と?を“区切り”として扱うと推定。
- 観察:
ステップ 3:キャッシュの解釈を検査(不一致探索)
Repeater で
/my-account?abc.jsに変更 → 送信。- 観察:キャッシュの痕跡なし(
X-Cache無し or 変化無し)→ キャッシュも?を区切りとして扱う可能性。
- 観察:キャッシュの痕跡なし(
次に
/my-account;abc.jsに変更 → 送信。- 観察:
X-Cache: miss+Cache-Control: max-age=30など → 静的拡張子.jsでキャッシュ対象。 - 同一 URL を再送 →
X-Cache: hit(キャッシュ配信に切替)。 - 推論:オリジンは
;を区切りと見なして/my-accountを返すが、キャッシュは;を区切りと見なさず/my-account;abc.jsを 静的.jsとして保存。この不一致が攻撃ベクトル。
- 観察:
ステップ 4:エクスプロイト作成(carlos を誘導して“彼のページ”をキャッシュ)
- Exploit server を開き、Body に以下(YOUR-LAB-ID と 任意トークン名を置換。前回と違う文字列にする):
<script>
document.location="https://YOUR-LAB-ID.web-security-academy.net/my-account;wcd.js";
</script>
Deliver exploit to victim をクリック。
- 意図:**carlos(ログイン済み)**が
/my-account;wcd.jsを取得 → オリジンは;を区切り、carlos の /my-account を返す → キャッシュは;を区切らず.jsとして保存。中身は carlos のページ。
- 意図:**carlos(ログイン済み)**が
ステップ 5:攻撃者がキャッシュされた carlos のレスポンスを取得
- TTL(例:30 秒)内に、攻撃者として同じ URL を開く:
https://YOUR-LAB-ID.web-security-academy.net/my-account;wcd.js
- 期待:本文に carlos の API キーが含まれる。コピーして Submit solution に貼り付けて完了。
7. トラブルシューティング(成功しない場合のチェック)
- X-Cache が常に miss:同一フル URL を再送しているか/TTL(max-age)内か。ヘッダで
Cache-Controlを確認。 - 自分のレスポンスが出る:任意文字列(例
wcd)を刷新し、新しいキャッシュキーを使う(以前の自分のキャッシュを踏むのを回避)。 - ? では効かないのは正常:キャッシュが
?をクエリ開始の区切りとして扱うため。;の方で試す。 - Intruder の結果が 404 ばかり:URL-encode しない設定になっているか、payload の候補が正しく読み込まれているかを確認。
- TTL 切れ:時間が過ぎたら再度 Deliver exploit → 即アクセス。
8. なぜこれが危険なのか(本質)
- 区切り解釈の不一致により、本来認証が必要な動的ページが、静的資産と誤認されてキャッシュされ、第三者に配布される。
- 個人データ/API キーの漏洩がワンショットで起きうる(アクセス制御をバイパス)。
9. 防御(実務で取るべき対策)
- 認証ページは常に
Cache-Control: no-store, private。 - キャッシュ層とオリジンのパス正規化を一致(
;/?/末尾スラッシュ/拡張子を揃える)。 - “静的拡張子”だけでキャッシュ判定しない:パス接頭辞(例
/my-account/*)を丸ごと非キャッシュに。 - 監視:
/my-account;*.jsのような不審な擬似静的パスのキャッシュヒットを検出。
10. 検証の確認ポイント(ラボでの成功条件)
/my-account;wcd.jsを開いて carlos の API キーが見える。- Submit solution でキーを提出 → Solved。
11. まとめ
オリジンは ; を区切りとして /my-account を返すが、キャッシュは ; を区切らず .js として保存 → 被害者でキャッシュ汚染 → 同 URL を攻撃者が閲覧して API キー取得(ラボクリア)。
Best regards, (^^ゞ