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)

教学文档

一、漏洞概述

  1. 受影响组件:H2O-3,一个由 H2O.ai 开发的开源分布式机器学习平台。
  2. 漏洞功能点ImportSQLTable 功能。该功能允许用户通过 JDBC(Java Database Connectivity)连接字符串从 SQL 数据库导入数据。
  3. 漏洞本质:由于对用户提供的 JDBC URL 校验不严,攻击者可构造恶意 URL,利用目标 Classpath 中存在的反序列化利用链(如 MySQL Connector/J 的 ServerStatusDiffInterceptor),在目标服务器上实现远程代码执行(RCE)。
  4. 漏洞类型:JDBC 反序列化漏洞(一种经典的攻击模式)。
  5. 影响版本: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 驱动会再次进行解码,最终正确解析出恶意参数。

三、漏洞调用链分析

漏洞的触发遵循清晰的代码执行路径:

  1. 入口点 (Entry Point):HTTP API 端点。请求由 water.api.RegisterV3Api#registerEndPoints 注册并路由。
  2. 功能处理 (Handler):请求被分发到 water.api.ImportSQLTableHandler#importSQLTable 方法处理。
  3. 核心业务逻辑 (Core Logic): handler 调用 water.jdbc.SQLManager#importSqlTable 方法。
  4. 安全校验 (Validation): 在 importSqlTable 中,会调用 SQLManager#validateJdbcUrl(url) 对用户输入的 JDBC URL 进行校验。此处正是被绕过的过滤点。
  5. 漏洞触发 (Trigger): 校验通过后,最终在 water.jdbc.SQLManager#getConnectionSafe 方法中,调用标准 Java API DriverManager.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. 利用过程

  1. 定位功能点:在 H2O-3 的 Web 界面中,找到通过 JDBC 导入数据的功能模块(通常为 Import SQL Table 或类似名称)。
  2. 准备恶意 MySQL 服务:使用 mysql-fake-server 等工具在攻击者控制的服务器上搭建一个伪装的 MySQL 服务器,该服务器会响应恶意序列化 payload。
  3. 生成 Payload:由于 H2O-3 项目依赖 Jackson 库,可利用已有的 Jackson 反序列化利用链(例如 org.springframework.context.support.FileSystemXmlApplicationContext 用于加载远程 XML 实现 RCE,或其他 Gadget)生成 payload。
  4. 构造并发送恶意 URL:在 H2O-3 的 JDBC 连接输入框中,填入构造好的恶意 URL。
    • 对于 CVE-2025-6507/5662:使用参数前加空格的格式。
    • 对于 CVE-2025-6544:对恶意参数名或值进行二次 URL 编码
  5. 触发漏洞:提交连接请求。如果绕过成功,H2O-3 服务器会尝试与恶意 MySQL 服务建立连接,从而触发反序列化并执行 payload 中的代码。

五、修复方案

  • 官方补丁:升级 H2O-3 至最新版本(> V3.46.0.8)。
  • 补丁核心改进
    1. 增强了 validateJdbcUrl 方法中的正则匹配逻辑,使其能够匹配参数前的空格。
    2. 加入了循环 URL 解码机制,确保将输入 URL 解码至最原始的形式,然后再应用黑名单过滤,从而有效防御多重编码绕过。

六、总结与启示

  1. 黑名单的局限性:该案例再次表明,依赖黑名单进行安全过滤往往存在被绕过的风险,尤其是在字符串解析和规范化(Normalization)层面。
  2. 安全校验应放在驱动之前:任何来自用户输入的、将传递给复杂第三方库(如 JDBC 驱动)的数据,都必须经过严格且充分的安全校验。
  3. 规范化与校验:对用户输入进行安全校验前,必须对其进行彻底的规范化(例如,完整的 URL 解码、路径标准化、大小写统一等),确保校验逻辑面对的是输入的“最终形态”。
  4. 威胁建模:对于支持 JDBC、JNDI 等可动态加载类机制的功能,应在设计阶段就充分考虑其潜在的反序列化攻击风险。

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 构造示例: 注意 ? 后的两个空格和 & 后的一个空格,它们成功绕过了正则检查。 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 API DriverManager.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 等可动态加载类机制的功能,应在设计阶段就充分考虑其潜在的反序列化攻击风险。