1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[writeup] picoCTF "SSTI1"

Posted at

今回の問題

picoCTFより"SSTI1"を解いていきます。

実際に解いていく

1. 問題文にあるWebサイトに移動する

SSTI1_1.png
このWebサイトでは、何かアナウンスをすることができるみたいです。

2. 適当な文字を入力してみる

SSTI1_2.png
「help!」と入力して[OK]ボタンをクリックすると、画面に大きな文字で表示されました。
以上が、このWebサイトの機能のようです。

3. ソースコード確認

SSTI1_3.png
SSTI1_4.png
ソースコードを確認してみました。
今回はHTMLのみです。怪しいところも見つかりません。

4. SSTIを疑う

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

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

5. 本当にSSTIなのか?

それでは、実際にSSTIなのかを検証していきましょう
SSTI1_5.png
まず、Webサイトの入力欄に

{{7 * 7}}

を入力します。
そして[OK]ボタンをクリックします。
SSTI1_6.png
すると、画面には入力した文字 " {{7 * 7}} " ではなく、49 という数字が表示されました!
これにて、SSTIが確定しました。

6. SSTIを利用してFLAGを獲得する

SSTI1_7.png
Webサイトの入力欄に、

{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' whoami ').read() }}

を入力して、ユーザー名「root」を取得します。

SSTI1_8.png
Webサイトの入力欄に

{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen(' ls ').read() }}

を入力して、ファイル一覧を取得します。
その中にflagファイルがありました!

SSTI1_9.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://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
サーバサイド・テンプレート注入 - SSTI脆弱性
サーバーサイド・テンプレート・インジェクション(SSTI)とは?
サーバーサイドテンプレートインジェクション

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?