サーバーサイドリクエストフォージェリ (SSRF)

サイバーセキュリティBeginner
オンラインで実践に進む

はじめに

サーバーサイドリクエストフォージェリ (SSRF) は、攻撃者がサーバーサイドのアプリケーションを誘導し、攻撃者が指定した任意のドメインに対して HTTP リクエストを送信させる Web セキュリティの脆弱性です。

重要な点は、リクエストを行うのが攻撃者自身ではなく、サーバーであるという点です。つまり、そのリクエストはサーバーのネットワーク上の位置、信頼関係、および内部限定の宛先へのアクセス権を継承することになります。

典型的な SSRF 攻撃では、攻撃者はサーバーを操作して、組織のインフラ内にある内部限定サービスへ接続させます。また、サーバーを強制的に任意の外部システムへ接続させ、認証情報などの機密データを漏洩させることもあります。

この実験では、シミュレートされた脆弱性のある Web アプリケーションを操作します。SSRF の脆弱性を特定する方法、基本的なセキュリティフィルタがどのように悪意のあるリクエストをブロックしようとするかを観察し、それらのフィルタを回避して、最終的に機密性の高い内部データやシミュレートされたクラウドメタデータを抽出する方法を学びます。共有の実験環境との互換性を保つため、シミュレートされたメタデータサービスではポート 80 の代わりに権限不要なハイポートを使用しています。

URL パラメータの特定

このステップでは、外部 URL からデータを取得するアプリケーションの機能を探すことで、SSRF の潜在的な脆弱性を特定する方法を学びます。

多くの Web アプリケーションは、他のサーバーからリソースを取得する必要があります。例えば、ソーシャルメディアサイトからプロフィール画像を取得したり、サードパーティの API からデータを取得したりするケースです。アプリケーションがユーザー入力として URL を受け取り、適切な検証を行わずにそれを取得する場合、SSRF に対して脆弱である可能性があります。

これが、SSRF が「URL 取得」という一見正当な機能の中に現れる理由です。危険な挙動は、製品の観点からは正常に見えるワークフローの中に隠されています。

ポート 8080 で脆弱性のある Web アプリケーションが起動しています。このアプリケーションには url パラメータを受け取る /check エンドポイントがあり、外部 Web サイトのステータスを確認するように設計されています。

http://example.com のような無害な外部 Web サイトを取得するようアプリケーションに要求することで、この機能をテストできます。ターミナルで curl コマンドを使用して、脆弱なアプリケーションに HTTP GET リクエストを送信してください。curl に馴染みがない場合は、リクエストを送信してサーバーの応答をターミナルに表示するシンプルなコマンドライン Web ブラウザだと考えてください。

curl "http://localhost:8080/check?url=http://example.com"

このコマンドを実行すると、ポート 8080 で実行されている脆弱なアプリケーションがリクエストを受け取り、url パラメータを抽出して、http://example.com に対して独自の HTTP リクエストを行います。その後、HTML の応答があなたに返されます。

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

サーバーが要求された URL のコンテンツを正常に取得して返したことを確認することで、url パラメータが実際に処理され、サーバーサイドのリクエストを行うために使用されていることがわかります。これが SSRF 脆弱性の最初の兆候です。

Localhost (127.0.0.1) に対する SSRF のテスト

このステップでは、SSRF の脆弱性を悪用して、サーバー上で実行されている内部サービスへのアクセスを試みます。

SSRF の最大の危険性は、リクエストを行うサーバーがネットワーク上で特権的な位置にあることが多いという点です。公開インターネットには露出していない内部サービスにアクセスできる可能性があります。今回のシナリオでは、ポート 5000 で実行されている内部管理パネルがあります。この管理パネルは 127.0.0.1 (localhost) にバインドされており、他のマシンからではなく、サーバー自身からしかアクセスできません。127.0.0.1 は、コンピュータが自分自身と通信している状態だと考えてください。

攻撃者として、ポート 8080 の SSRF 脆弱性を利用し、サーバーを騙してポート 5000 の管理パネルに代わりにアクセスさせることができます。

脆弱な /check エンドポイントにそのローカル URL を渡して、内部管理パネルへのアクセスを試みてください。

curl "http://localhost:8080/check?url=http://127.0.0.1:5000/admin"

このコマンドを実行すると、リクエストが成功しないことに気づくでしょう。代わりにエラーメッセージが表示されます。

Error: Localhost access is blocked by WAF!

開発者は、SSRF 攻撃を防ぐために Web アプリケーションファイアウォール (WAF) や入力フィルタを実装することがよくあります。この場合、アプリケーションは提供された URL に 127.0.0.1 または localhost という文字列が含まれているかどうかをチェックします。入力がこのフィルタに一致したため、アプリケーションはリクエストをブロックしました。

単純な文字列フィルタは、ネットワークの宛先には複数の等価な表現が存在するため、脆弱です。防御側は、単なるリテラルテキストではなく、ネットワーク上の意味を理解した検証を行う必要があります。

アプリケーションがどのように入力をフィルタリングしているかを理解することは、SSRF を悪用する上で重要なステップであり、どのような制限を回避する必要があるかを知る手がかりになります。

入力フィルタの回避

このステップでは、前のステップで遭遇した基本的な入力フィルタを回避する方法を学びます。

回避テクニックが有効なのは、URL の解析、ホスト名の解決、および入力フィルタリングが常に同じ解釈ルールを使用しているわけではないためです。

単純な文字列一致(127.0.0.1 のブロックなど)に依存する入力フィルタは、IP アドレスが複数の方法で表現できるため、欠陥があることが多いです。オペレーティングシステムのネットワークスタックは、これらの代替表現を同じ宛先に解決しますが、アプリケーションのテキストフィルタはそれらを認識できない場合があります。

以下に、不適切に実装されたフィルタを回避できる可能性のある、localhost IP アドレス (127.0.0.1) の一般的な表現方法をいくつか挙げます。127.1 のような短縮 IP、2130706433 のような 10 進数 IP、0177.000.000.001 のような 8 進数 IP、または 0x7f000001 のような 16 進数 IP を使用できます。

アプリケーションは 127.0.0.1 と localhost という正確な文字列のみをブロックしているため、短縮 IP 表現である 127.1 を使用してフィルタを回避し、内部管理パネルにアクセスできます。

次のコマンドを実行して、回避テクニックをテストしてください。

curl "http://localhost:8080/check?url=http://127.1:5000/admin"

127.1 はブロックされた文字列と一致しないため、アプリケーションはリクエストの続行を許可します。サーバーのネットワークスタックは 127.1 を 127.0.0.1 に解決し、内部管理ページを正常に取得します。

Welcome to the Internal Admin Panel. Secret Key: SSRF_ADMIN_SUCCESS

入力フィルタを正常に回避し、SSRF の脆弱性を悪用して制限された内部サービスにアクセスできました。

内部メタデータへのアクセス

このステップでは、SSRF の脆弱性を利用して機密性の高いクラウドメタデータにアクセスします。

アプリケーションがクラウド環境(AWS、Google Cloud、Azure など)でホストされている場合、169.254.169.254 という特別なルーティング不可能な IP アドレスにアクセスできることがよくあります。このアドレスはインスタンスメタデータサービス (IMDS) をホストしており、実行中のクラウドインスタンスに関する情報(非常に機密性の高い一時的な IAM (Identity and Access Management) 認証情報を含む)を提供します。「ルーティング不可能」とは、そのアドレスが一般的なパブリックインターネットアクセス用ではなく、ローカルのクラウドインフラストラクチャ用であることを意味します。

攻撃者がクラウドホスト型のアプリケーションで SSRF の脆弱性を発見した場合、このメタデータエンドポイントへのクエリは、クラウド環境の完全な侵害につながる可能性があるため、多くの場合、主要な目標となります。

この実験環境では、シミュレートされたクラウドメタデータサービスが 169.254.169.254:8000 で実行されています。実際のクラウドメタデータサービスは通常ポート 80 を使用しますが、この実験では特別な権限なしでサービスを開始し、他のソフトウェアと競合しないように意図的にポート 8000 を使用しています。まず、SSRF の脆弱性を利用して、利用可能なメタデータディレクトリをリストアップします。

curl "http://localhost:8080/check?url=http://169.254.169.254:8000/latest/meta-data/"

サーバーはメタデータディレクトリのリストを取得し、あなたに返します。

iam/security-credentials/admin-role

出力から admin-role という名前の IAM ロールが明らかになりました。このパスを SSRF のペイロードに追加することで、このロールに関連付けられた実際のセキュリティ認証情報を抽出できます。

次のコマンドを実行して、機密性の高い認証情報を取得してください。

curl "http://localhost:8080/check?url=http://169.254.169.254:8000/latest/meta-data/iam/security-credentials/admin-role"

シミュレートされたメタデータサービスが、JSON 形式の認証情報を返します。

{"AccessKeyId":"AKIAIOSFODNN7EXAMPLE","SecretAccessKey":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}

このリクエストでデータが返されない場合は、/tmp/meta.log を確認し、169.254.169.254:8000 でサービスがリッスンしていることを確認してください。

これらの認証情報を正常に抽出することで、クラウド環境における SSRF 脆弱性の深刻な影響を実証しました。

まとめ

この実験では、サーバーサイドリクエストフォージェリ (SSRF) の脆弱性を調査し、悪用することに成功しました。サーバーサイドでの取得動作を観察することで、脆弱な URL パラメータを特定する方法を学びました。次に、ローカルアクセスをブロックするように設計された基本的な入力フィルタに遭遇し、代替の IP アドレス表現を使用してそれを回避しました。最後に、機密性の高いシミュレートされたクラウドメタデータの認証情報を抽出することで、SSRF の重大な影響を実証しました。これらのテクニックを理解することは、セキュリティ評価中に脆弱性を特定するため、および Web アプリケーションに堅牢な防御を実装するために不可欠です。