Hello there, ('ω')ノ
1. SSTIとは何か
SSTI(Server-Side Template Injection)は、 サーバ側テンプレートエンジンの機能を悪用して、意図しないコードを実行させる攻撃手法です。
例:
- Flask (Jinja2)
- Django (Template Engine)
- Ruby on Rails (ERB)
- Twig (PHP)
- Velocity (Java)
攻撃対象:
- テンプレート内にユーザ入力がそのまま埋め込まれる場面
2. 検出までの考え方と流れ
ステップ1: テンプレートエンジンを特定する
方法
- レスポンスヘッダーやエラーメッセージから判定
- フォームやパラメータで意図しない値を送信してみる
例
{{7*7}} → 49
→ この時、7*7の結果がそのまま表示されればSSTIの可能性が高い
ステップ2: フィルタリング・サニタイズを確認
- 一部フィルターが入っていても、 エスケープされていない場所を探す
テスト文字列一覧
{{1337*1337}}${1337*1337}<%= 1337*1337 %>{{config}}
ステップ3: テンプレートエンジン固有の機能悪用
例:Jinja2(Python)
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen("id").read() }}
目的: Pythonオブジェクトの属性をたどり、
osモジュールやpopenを呼び出す。注意: 全ての環境で機能するわけではない。
例:Twig(PHP)
{{ system("id") }}
3. 実際に使えるチェックリスト(一般化済み)
以下は、SSTI発見から悪用までに活用できるチェック項目です。
✅ 初期調査
- [ ] テンプレートエンジンの種類を推測
- [ ] レスポンス内に
{},${},<% %>などがそのまま返らないか確認 - [ ] エラーメッセージにテンプレートエンジン関連の単語が含まれていないか確認
✅ テンプレートインジェクション確認
- [ ]
{{7*7}}や${7*7}など基本テストペイロード送信 - [ ] 結果が評価・計算されるか観察
- [ ] テンプレート内にフィルターがかかっていない箇所を探す
✅ 環境固有のRCE試行
- [ ] Python/Jinja2:
self._TemplateReference__context経由で属性をたどる - [ ] PHP/Twig:
{{ system("id") }}など関数呼び出し確認 - [ ] Java/Velocity:
#set()や#evaluate()構文利用 - [ ] Ruby/ERB:
<%= %>内でコマンド評価
✅ 防御・フィルタリング確認
- [ ] テンプレートエンジン側の設定で
autoescapeが有効か確認 - [ ] Sandbox機能が有効か確認
- [ ] CSP(Content Security Policy)など他レイヤーの防御有無
4. 補足:CTFや実務での注意点
- エンジンによって文法が異なるため、最初に軽い数式テストをすることが重要
- フレームワーク標準設定以外(カスタマイズ)も考慮すること
- 一発で成功しない場合は複数パターンを試すこと
おわりに
SSTIは発見まで難しい場合もありますが、 今回まとめたように体系的に試行することで検出可能性を上げることができます。
このチェックリストをベースに、自分なりの項目を追加しながら活用してみてください。
Best regards, (^^ゞ