freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Jdbc反序列化[绕过|修复|分析]
2023-09-12 13:08:47

前言

此文章主要是对mysql Jdbc驱动连接过程的分析,本次分析使用的mysql-connector-java版本为8.0.14。

0x01 jdbc标准流程

oracle约束的jdbc建立连接的标准流程其他的数据库只需要按照这套标准实现自己的连接驱动即可,我们只关注其建立连接的步骤,之后的数据交互不做分析。oracleJDBC官方文档

mysql connector/j开发指南

总结后,jdbc的连接流程如下:

  1. 注册数据库连接驱动,比如:Class.forName("com.mysql.cj.jdbc.Driver")

  2. 连接数据库,比如:Connection con= DriverManager.getConnection(c,properties);

0x02 mysql jdbc连接流程

我们直接来到mysql的连接流程,驱动会调用mysql驱动com/mysql/cj/jdbc/NonRegisteringDriver.java的connect()函数。connect()函数的具体处理流程如下:

  1. 判断是否能处理连接字符串,使用正则提取:之前的部分比如jdbc:mysql:作为scheme。

  2. 对连接url进行处理,将其转换为ConnectionUrl对象。转换的过程包括

    • 通过正则匹配将连接url分为schemeauthoritypathqueryfragment正则代码在ConnectionUrlParser.java的CONNECTION_STRING_PTRN中。由于fragment是从#开始匹配,所以在jdbc反序列化中我们可以直接将连接字符串跟在数据库名后面再通过#号将后面原有的query字段改为fragment部分,达到截断链接字符串的目的。

    • 如果设置了useConfigs参数,则可以设置连接配置文件。从中读取配置信息。详见com/mysql/cj/conf/ConnectionUrl.java#expandPropertiesFromConfigFiles

    • 将连接url的参数转换为properties,在转换时会将参数的key和value都urldecode解码一下,所以该点可能存在连接字符绕过的风险。详见com/mysql/cj/conf/ConnectionUrlParser.java#processKeyValuePattern

    • 将getConnection时携带的Properties参数加入url属性当中,如果在url中定义了该属性则覆盖。在getConnection时传入的user和password就输入Properties参数,用户可以在Properties中加入更多的url参数。

    • 在创建HostInfo时参数设置有protocol=PIPE和path参数时就可以在path位置创建PIPE文件。详见
      com/mysql/cj/conf/ConnectionUrl.java#fixProtocolDependencies

  3. 接着,会初始化ConnectionImpl类(默认jdbc:mysql://)在初始化过程中驱动会根据连接url中携带的参数来设置缓存区、代理和查询拦截器。

    • 查询拦截器就是引起jdbc反序列化的地方,在url连接参数中可以通过设置QueryInterceptors参数来指定SQL语句查询结果的处理过程。所以我们设置为com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor时,当我们获取查询结果时,处理流程就会来到ServerStatusDiffInterceptor的postProcess函数中,接着触发postProcess->populateMapWithSessionStatusValues->ResultSetUtil.resultSetToMap->ResultSetImpl.getObject。最后在数据类型为BLOB以及url参数autoDeserialize=True的情况下触发objIn.readObject()。

    • 只要实现了QueryInterceptor的类都可以作为查询拦截器。

  4. 至此mysql JDBC就已经完成了连接。

0x03 JDBC反序列化关键字绕过

通过0x02里我们对连接流程的分析我们可以总结出以下几个值得关注的点:

  • mysql-connector/j 8.x的连接过程中会将#后面的部分认为是fragment所以我们可以通过#来阶段url连接字符,所以当遇到对数据库名中的autoDeserialize和queryInterceptors做过滤时,我们可以尝试在数据库ip或者端口参数后面加入/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#来完成关键字的绕过。关于这一点是否在5.x、6.x有效,笔者没有分析,不过大可一试!

  • mysql-connector/j 8.x的连接过程中会对参数名和数值进行url解码,所以在遇到对所有参数中的autoDeserialize和queryInterceptors做过滤时我们可以尝试单次/多次url编码关键字来绕过,例如:%61utoDeserialize、%2561utoDeserialize。需要注意的是笔者在5.x版本的连接过程中发现并不会进行url解码。

0x04 修复方案

  1. 对于jdbc反序列化来说,可以通过将mysql-connector/j升级到8.0.21来解决该问题,在mysql-connector/j8.0.21的ServerStatusDiffInterceptor#populateMapWithSessionStatusValues中不再使用getObject而是使用getString。

image-20230911172541479

image-20230911172716088

image-20230911172957555

  1. 同时也可以在getConnection时提前设置好properties中autoDeserialize属性为false。这样即使攻击者在连接url中设置了autoDeserialize参数也会被覆盖掉。

String c="jdbc:mysql://127.0.0.1:3306/test";
Properties properties=new Properties();
properties.setProperty("autoDeserialize","false");
properties.setProperty("user","1");
properties.setProperty("passwd","2");
Connection con= DriverManager.getConnection(c,properties);

创作不易,转载需注明出自公众号"地表最强伍迪哥"

qrcode_for_gh_1b982131f697_344

# 反序列化漏洞 # Java反序列化漏洞分析 # JDBC
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录