Python-Flask-SSTI

1. Flask框架
Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。
2. flask基础
a. 一个基础的Flask代码

from flask import Flask 导入了Flask框架
app=Flask(__name__) 
@app.route('/') route装饰器的作用是将函数与URL绑定起来。这里的作用就是当访问 
def index(): 127.0.0.1:5000时,flask就会返回hello flask
return '<h1>hello flask</h1>'
if__name__=='__main__':
app.run(debug=True)

b. 渲染方法 flask的渲染方法有render_template和render_template_string两种
i. render_template()是用来渲染一个指定文件的,使用如下
return render_template('index.html')
ii. render_template_string()则是用来渲染一个字符串的,SSTI与这个方法密不可分。使用方法如下
html = '<h1>This is hello page</h1>'
return render_template_string(html)
c. 不正确的使用flask中的render_template_string方法会引发SSTI。当代码和数据混淆,并且用户输入的数据会和HTML拼接后进行渲染,就可能会产生SSTI

3. jinjia2
a. jinjia2是Flask作者开发的一个模板系统,起初是模仿django模板的一个模板引擎,为Flask提供模板支持,由于其灵活性,快速和安全被广泛使用。
flask是使用Jinjia2来作为渲染引擎的,网站根目录下新建templates文件夹,就是用来存放html文件的。
b. 在jinjia2中有三种语法
控制结构 {% %}
变量取值 {{ }}
注释{# #}
c. jinjia2模板中使用{{ }}语法表示一个变量,它是一种特殊的占位符。当利用jinjia2渲染时,它会把这些特殊的占位符进行填充或者替换,jinjia2支持python中所有的python数据类型,比如列表、字段、对象。
d. jinja2中的过滤器可以理解为是jinja2里面的内置函数和字符串处理函数。
被两个括号包裹的内容会输出其表达式的值
4. 漏洞利用
a. 构造payload的原理
首先要知道python所有类的几个魔法方法:
__class__ 返回类型所属的对象(类)
__mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ 返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ 类的初始化方法
__globals__ 对包含函数全局变量的字典的引用
payload构造思路:从一个内置变量调用__class__.base__等隐藏属性,去找到一个函数,然后调用调用其__globals['builtins']即可调用eval等执行任意代码。
(builtins即是引用,Python程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于builtins却不用导入,它在任何模块都直接可见,所以这里直接调用引用的模块)
也就是通过Python的对象的集成来一步步实现文件读取和命令执行的。
b. payload构造步骤
i. 获取字符串的类对象(获取一个类)
>>> 'a'.__class__
<type 'str'>
ii. 2.寻找基类链,找到<type 'object'>类
>>> 'a'.__class__.__mro__
(<type 'str'>, <type 'basestring'>, <type 'object'>)
iii. 3.寻找<type 'object'>类的所有子类中可用的引用类
>>> 'a'.__class__.__mro__[2].__subclasses__()
这里可以看到有一个<type 'file'>类,也就是对文件操作的类,那么可以拿他的方法进行文件读取。
iv. 利用<type 'file'>的read()方法进行文件读取
'a'.__class__.__mro__[2].__subclasses__()[40]('/Users/rebecca/Sites/info.php').read()

5.注意事项

  1.对于Flask模板注入,首先是要判断是否为注入点,即通过输入表达式{{1+1}}观察程序是是否执行,输出结果。
  2.__mro__与__base__的区别在于,__mro__返回的是一个对象所属的类继承的全部类,可以有很多个。__base__返回的是其继承的基类,只有一个。
  3.__subclasses__该模块是查询到的结果是一个类的全部子类,我们需要在这些子类中寻找可以利用的子类。这个模块返回的数据往往有很多,可以通过将这些数据存入到List,通过list.index('')来输出所需要的的模块所在的位置。可以利用的子类:        warnings.catch_warnings、socket._socketobject、site._Printer等模块。
  4.__builtins__是python的内置模块,内含有python内置的函数。可以通过此模块来调用内置函数如:eval、exec、open。也正是可以利用这些方法进行命令执行、文件读取。
  5.os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作。os模块中可以利用的函数:system(command)运行shell命令、listdir(dirname)列出dirname下的目录和文件、popen从一个命令打开一个管道进行文件读取等。
   6.区分python2和python3可以查找__builtins__中是否有file有file的话是2没有的话是3

 <a href="https://md5.cc">md5解密</a>

posted @ 2020-10-16 21:16  二算i  阅读(433)  评论(0编辑  收藏  举报