上次去参加BCTF,第一道AWD题目就是Flask的SSTI漏洞,当时由于不熟悉Flask框架,,所以一开始没意识到这是模板命令注入的漏洞,,直到抓到别人的流量才知道了payload,,回来之后好好学了下Flask框架。
整得来说Flask真的只能算轻量级应用,,代码构成也比较简单,出现的漏洞问题跟PHP大同小异,没有什么的有意思的函数漏洞,可能是自己水平不够吧。。
flask网上开源的cms很少,所以只能在github上找,,如果哪天源码网站上出现大批量的flask应用,,或许flask的运用才真的谈得上广泛!
这次审计flaks的github地址为:https://github.com/yubang/cms
0x00 环境搭建
这里一开始用的Macbook搭建的,首先搭建virtualenv,,安装flask,这个都没什么好说的。
问题就出现在安装MySQLdb库时出现了问题,,如果使用pip这样的安装问题,,一直报错,,然后找问题,,修改,,继续报错。。后来放弃了在macbook上搭建,改而使用windows环境搭建
这里windows环境已经集成好了MySQLdb的whl文件,直接安装即可,不过这里注意下,要在virtualenv环境下安装whl文件,还有一种就是提供了exe的安装方式,这种也可以,,不过不是虚拟环境下,,因此当运行虚拟环境时,系统仍然会提示这个库文件是找不到的~
0x01 代码审计
整个cms不是很大,,因为自己也是刚学flask,如果上来就用一个很大的cms来练手,似乎有点不妥,,所以选择了这款小型cms来审计。
这里就从这个登录框开始审计,在第一次看代码时就感觉有问题,,后来环境搭建好了,,这里果然存在问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@app.route(“/login”,methods=[‘POST’])
def login():
“登录”
username=request.form.get(“username”,None)
password=request.form.get(“password”,None)
global db
dao=db.M(“cms_account”)
result=dao.where({“username”:username,“password”:password}).count()
if(result==1):
session[‘uid’]=time.time()
return redirect(“/admin”)
else:
return redirect(“/?error=1”)
|
这里类似于php,通过传参username和password,然后进入到数据库的查询,,我们跟进这里的where语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
def where(self,data=None):
if(data==None):
pass
elif(type(data)==dict):
keys=data.keys()
index=0
while(index<len(keys)):
if(type(data[keys[index]])==type([])):
value=data[keys[index]][1]
fuhao=data[keys[index]][0]
fuhao=fuhao.upper()
if(fuhao==“GT”):
fuhao=” > “
value=self.__dealField(value,True)
elif(fuhao==“GTE”):
fuhao=” >= “
value=self.__dealField(value,True)
elif(fuhao==“LT”):
fuhao=” < “
value=self.__dealField(value,True)
elif(fuhao==“LTE”):
fuhao=” <= “
value=self.__dealField(value,True)
elif(fuhao==“EQ”):
fuhao=” == “
value=self.__dealField(value,True)
elif(fuhao==“NEQ”):
fuhao=” != “
value=self.__dealField(value,True)
elif(fuhao==“LIKE”):
fuhao=” LIKE “
value=self.__dealField(value,True)
elif(fuhao==“BETWEEN”):
fuhao=” BETWEEN “
value=value[0]+” AND “+self.__dealField(value[1],True)
elif(fuhao==“NOT BETWEEN”):
fuhao=” NOT BETWEEN “
value=value[0]+” AND “+self.__dealField(value[1],True)
elif(fuhao==“IN” or fuhao==“NOT IN”):
if(fuhao==“IN”):
fuhao=” IN “
else:
fuhao=” NOT IN “
v=“”
i=0
for temp in value:
if(i!=0):
v=v+“,”
v=v+self.__dealField(temp,True)
i=i+1
v=“(“+v+“)”
value=v
else:
value=self.__dealField(data[keys[index]],True)
fuhao=“=”
if(index!=0):
self.__whereText=self.__whereText+” AND “
else:
self.__whereText=” WHERE “
self.__whereText=self.__whereText+self.__dealField(keys[index],False)+fuhao+value
index=index+1
else:
self.__whereText=data
return self
|
这里代码很冗长,,其实很简单!
这里首先判断where里面有无数据,如果没有数据,直接pass,如果有数据并且是dict类型,进入下面的语句
然后就是得到这里的fuhao参数,由于这里没有任何像LIKE或者IN这样的语句,因此可以直接跳过对fuhao的判断
也就是说直接进入到了else
1
2
3
|
else:
value=self.__dealField(data[keys[index]],True)
fuhao=“=”
|
那么这里继续跟进dealField函数
1
2
3
4
5
6
7
8
9
10
|
def __dealField(self,data,sign):
“处理字段,防止sql注入”
if(data==None):
return ‘null’
if(type(data)!=str and type(data).__name__!=“unicode”):
data=str(data)
data=re.sub(r”’,‘\’‘,data)
if(sign and data != None):
data=”‘“+data+”‘”
return data
|
这里就是问题的核心所在,,首先判断数据类型,然后强制转化为str类型
核心语句为re.sub函数,这个相当于replace函数,意思就是将单引号给他加上一个转义符号
也就是我们如果输入admin’,那么这里就会变成admin’
这里回到原点,密码处没有进行MD5加密,直接用的原文
因此这里就出现了一个安全问题,,那就是我们使用转义符号将原本的单引号给转义,然后密码处填上我们的sql语句即可
这种思路的确是可行的
这里由于count后的数据不能为0,因此这里构造万能语句,,就能让count为1,即可绕过前台登录
这里其实有两种poc
1)username=123&password= or 11=11#
2)username=’ or 11=11#&password=qwer
这里直接就登录进来了~
后面的洞就比较没啥意思了。。这里存在的一个功能就是提供信息的展示,这里的参数都没有过滤,因此存在xss漏洞
本来想找找getshell的漏洞,,一直没找到其他漏洞,,后来自己构造了一个模板注入漏洞
1
2
3
4
5
|
@app.route(“/test”)
def test():
name = request.args.get(‘name’)
template = ”‘hello %s!’” % name
return render_template_string(template)
|
这里jinja2对{{balabala}}里面的数据会进行解析,,也就说会直接执行里面的命令,如果想要快速定位SSTI漏洞的话,直接全局搜索render_template_string
http://127.0.0.1:8000/test?name={{().__class__.__bases__[0].__subclasses__()[40](“D://test.txt”).read()}}
0x02 后续
这次由于cms的代码过少,,所以没什么可以审计的点,,如果后面有好的漏洞点,,可以作为flask的漏洞代表,再拿出来说吧!
偶然发现的一个CTF网站,好像是燕京理工学院的一个小比赛,题目不是很多,也不是很难,适合新人入门CTF,以下附上这个小型CTF的wp,题目地址:传送门 1.签到题 签到题总是很简单,可是这种简单程度第一次见。。。连动都不动的,直接告诉答案。。 …
请登录后发表评论
注册