最近一直在和python打交道,就想顺便学点Flask漏洞,也算打打python后端框架基础吧。
Flask搭建后端服务
众所周知python也可用用来写后端,最简单的框架就是Flask,例如:
1 | from flask import Flask |
上面的python文件运行时会在5000端口跑web服务,访问https://IP:5000/ 返回hello world!的字符串。
上面的例子为返回简单的字符串,也可用模板渲染html源码在浏览器显示:
1 | from flask import Flask,render_template,render_template_string |
在浏览器中访问显示如下:
即html字符串中的标签被模板渲染并显示在浏览器中。
Flask模板注入漏洞原理
而当字符串中的具体参数可控时,就可能存在模板注入漏洞:
1 | from flask import Flask,request,url_for,redirect,render_template,render_template_string |
而构造js代码就可能造成XSS攻击
此时传参的code直接插入字符串中,并被render_template_string渲染而触发SSTI。
只要换种写法就能避免:
1 | from flask import Flask,request,url_for,redirect,render_template,render_template_string |
这是因为模板引擎一般都默认对渲染的变量值进行编码转义,因此用户控制的不是模板而是变量,并不会得到渲染产生SSTI。
基于SSTI的攻击
jinja2模板引擎会对{{}}内的内容进行渲染,也可执行一些表达式:
或查看全局常量:
可见表达式和命令都被执行了,由此可构造文件包含漏洞
与反序列化类似,同样需要利用魔术方法构造漏洞链,常用魔术方法:
- class 返回类型所属的对象
- mro 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
- base 返回该对象所继承的基类
- __base__和__mro__都是用来寻找基类的
- subclasses 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
- init 类的初始化方法
- globals 对包含函数全局变量的字典的引用
思路一般为先用{{''.__**class__**}}(注:此处不是双引号而是两个单引号)找类型所属对象,然后{{''.__**class__**.__**mro__**}}查找所有基类
然后即可查找所有可用的类