レッスン 2-5
サーバーを踏み台にした内部への到達
外の
利用者の
なぜ通るのか
画像の
ここで、
サーバーサイドリクエスト
外と内が混ざる所
サーバーは、
利用者の
クラウドの設定の置き場
クラウドの169.254.169.254 の
機械の
IP の許可リストだけでは足りない
「内側の
確かめは、
脆いコードと直したコード
ラボの127.0.0.1:8081 で、127.0.0.1:8080 で、
行き先を確かめるか
from urllib.request import urlopen def fetch(url):with urlopen(url, timeout=5) as r:return r.read()from urllib.parse import urlsplit ALLOW = {"img.example.com"} def check(url):u = urlsplit(url)if u.scheme != "https":raise ValueError("scheme")if u.hostname not in ALLOW:raise ValueError("host")return u.hostname脆い方に、http、住所は 127.0.0.1:8081、道は /admin) をscheme) でhttps にhost の
利用者が
名前を引いたあとの住所を確かめるか
def allowed(host):return host in ALLOWimport socketfrom ipaddress import ip_address def public_ips(host):infos = socket.getaddrinfo(host, 443)ips = sorted({i[4][0] for i in infos})for ip in ips:if not ip_address(ip).is_global:raise ValueError("inside " + ip)return ips許可したlocalhost を127.0.0.1 がis_global が
ただし、
転送を追いかけるか
from urllib.request import urlopen def get(url):with urlopen(url, timeout=5) as r:return r.read()from urllib.request import (build_opener, HTTPRedirectHandler) class NoFollow(HTTPRedirectHandler):def redirect_request(self, *a):return None OPENER = build_opener(NoFollow) def get(url):with OPENER.open(url, timeout=5) as r:return r.read()ラボの 127.0.0.1:8080 は、127.0.0.1:8081/admin へ
OWASP も、
ログでの見え方と検知
SSRF の
fetch refused host=localhostip=127.0.0.1 reason=insideuser=1042 feature=avatarこの
| 見る物 | な |
|---|---|
| 断った | ふだんの |
| 引いた | 2 つが |
| 転送の | 取りに |
クラウドでは、
直し方と、直ったことの確かめ方
自分の
- 作業用の
フォルダで、 内側の サービスを 127.0.0.1:8081に立てる。 127.0.0.1:8080には、8081への転送を 返すサーバーを立てる - 脆い
fetchに8081の URL を、脆いgetに8080のURL を 渡し、 どちらも 内側の 答えを 持ち帰る ことを 確かめる - 脆い
allowedにlocalhostを渡し、 通ってしまう ことを 確かめる - 関数を
直した コードに 置き換え、 同じ入力が scheme、inside、302 で 止まる ことを 確かめる - 下の
試験を 足し、 直す前の コードに 戻すと 試験が 落ちる ことも 確かめる - 終わったら、
2 つの サーバーを 止め、 作業用の フォルダごと消す
import pytest def test_inner_url_refused():with pytest.raises(ValueError):check("http://127.0.0.1:8081/") def test_name_to_inside_refused():with pytest.raises(ValueError):public_ips("localhost")試験はget が
あわせて、
関わる事例
CISA は
JPCERT/CC も、
確認クイズ
1 問目
画像を
- ア 許可した
名前が、 内側の 住所を 指すように 書き換えられたとき - イ URL が
https で 始まるとき - ウ 画像の
大きさが 大きいとき
答えと理由を見る
答え ア
URL に
2 問目
URL も、
- ア 最初の
URL を 確かめたので、安全 - イ 転送の
先は 確かめを 通っていないので、 内側に届く - ウ 転送は、
ブラウザだけが追う
答えと理由を見る
答え イ
確かめたのは
説明課題
次の
- IP の
許可リストだけでは SSRF を 防げない理由
模範解答を見る
URL に
一次資料
どれも
- Server Side Request Forgery Prevention Cheat Sheet (OWASP、英語)。
許可リスト、 転送の 追い かけを 切る こと、 DNS の 固定の 問題、 許可リストを 持てない 場合、 各クラウドの メタデータの 住所の表 - Use the Instance Metadata Service to access instance metadata (AWS、英語)。
IMDSv2 の PUT で 取る トークン、 X-Forwarded-For 付きの PUT を 断る こと、 hop limit の 既定が 1 - Access instance metadata for an EC2 instance (AWS、英語)。
IMDS から AWS の セキュリティの 認証の 情報を 取れること - AA24-060B Threat Actors Exploit Multiple Vulnerabilities in Ivanti Connect Secure and Policy Secure Gateways (CISA、英語)。
2024年2月29日の 注意喚起。 CVE-2024-21893 が SAML の 部品の SSRF であること - Ivanti Connect Secureおよび
Ivanti Policy Secureの 。脆弱性 (CVE-2023-46805および CVE-2024-21887)に 関する 注意喚起 (JPCERT/CC、 日本語) 2024年1月31日 (現地時間) の SSRF の 脆弱性 CVE-2024-21893 の修正
次へ
次の