什么是JDBC反序列化漏洞?

JDBC在连接目标服务时,存在反序列目标服务传回的数据的机制,如果目标服务是恶意,可以精心构造这一部分数据,那么发起JDBC连接的客户端就会受到攻击,所以该部分的攻击点是可以控制连接目标的地址,指向攻击者构造的服务器地址,而不是控制连接数据

这里注意几个概念,JDBC是是Java提供对数据库进行连接抽象API接口,具体的内容是不同的数据库提供商实现的

JDBC反序列机制探究

相关依赖

SQL

mysql
mysql-connector-java
8.0.19


commons-collections
commons-collections
3.2.1

客户端测试代码

SQL
public class App {
public static void main(String[] args) throws Exception {
String ClassName = “com.mysql.jdbc.Driver”;
String JDBC_Url = “jdbc:mysql://localhost:3306/test?”+
“autoDeserialize=true”+
“&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor”;
String username = “root”;
String password = “root”;
Class.forName(ClassName);
Connection connection = DriverManager.getConnection(JDBC_Url, username, password);
}
}

基础理解

不常见的可能是参数autoDeserialize=true和&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor部分

autoDeserialize=true:这是一个连接参数,表示自动反序列化结果集

queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor:这是一个查询拦截器,用于在查询执行前后执行一些操作。ServerStatusDiffInterceptor 是MySQL Connector/J提供的一个拦截器,用于在查询执行前后检查服务器状态的变化。

当设置了ServerStatusDiffInterceptor查询拦截器时,查询的数据就会经过查询拦截器处理,拦截器会检查服务器的状态,如字符集、时区等,确保与客户端配置一致

当设置了autoDeserialize=true时,会自动反序列化服务器返回的二进制数据(如 BLOB 类型)

注:这里的autoDeserialize 是 MySQL JDBC 驱动的一个属性,而不是拦截器的属性

设置autoDeserialize=true时确保会反序列化服务端返回的数据,设置ServerStatusDiffInterceptor查询拦截器确保有数据可供反序列化

具体来说,拦截器会读取服务器返回的某些字段(如 STATUS_SESSION_TRACK_SYSTEM_VARIABLES),这些字段可能包含二进制数据。如果启用了 autoDeserialize=true,这些二进制数据会被反序列化。

两者间的联系:

autoDeserialize=true:提供了反序列化的功能。如果没有启用该属性,即使服务器返回了恶意二进制数据,JDBC 驱动也不会尝试反序列化,从而无法触发漏洞。

ServerStatusDiffInterceptor:提供了触发反序列化的途径。该拦截器会在连接建立后主动向服务器发送查询请求,并读取服务器返回的二进制数据。如果没有该拦截器,攻击者可能难以找到合适的时机和方式将恶意二进制数据传递给客户端。

过程调试

首先断DriverManager.getConnection

步入到connect方法,会进入到SINGLE_CONNECTION分支

进入到getInstance方法,来到createNewIO

进入connectOneTryOnly

在里面设置拦截器

要跟的层数有点多,不过方法都一样,在设置完拦截器后,拦截器会执行sql语言SHOW SESSION STATUS查询

处理查询返回结果

处理返回结果中使用反序列化处理

值得一提的是跟进这里里面不是 new ObjectInputStream() ois.readObject()这种形式,而就单单是getObject方法

调用栈如下