JDBC反序列化-Mysql

JDBC反序列化

Mysql

环境设置

$5.1.11\leq$

  1. mysql-connector-java-5.1.26

  2. commons-collections-3.2(用来打反序列化链)

payload

  1. fake_mysql_server

    https://wiki.wgpsec.org/knowledge/ctf/JDBC-Unserialize.html

  2. payload

漏洞分析

  1. 调用堆栈
  1. DriverManager#getConnection跟进之后,在ConnectionImpl#connectOneTryOnly中设置拦截器(拦截器的作用是在查询语句执行前后,拦截影响最终的执行结果)。
  1. 接着跟进com.mysql.jdbc.ConnectionImpl#loadServerVariables最后会到执行函数executeQuery来执行拼接的sql语句。

    1. 接着一直调用到com.mysql.jdbc.MysqlIO#sqlQueryDirect方法时,判断statementInterceptors是否为空,不为空则调用之前url中写入的ServerStatusDiffInterceptor,这里的判断很有意思,写了一堆,最后可以只由一个条件this.statementExecutionDepth == 1决定,这个条件由之前执行过一次的sqlQueryDirect自加,初始化的时候是0,满足条件。
    1. 接着调用到查询SHOW SESSION STATUS的地方,通过这个查询获取恶意类
    1. 想要进行readObject还需要去设置前面url中的参数autoDeserialize=true

    2. 然后很奇怪的是,用网上使用的mysql服务器不知道为什么需要加多一行才能出发反序列化的过程

    3. 分析数据包

  1. 这里是调用sink:getObject的函数,而第一次getObjectcolumn=1的时候,不会调用readObject,所以关注点放在第二次get

  2. getObject(2)的时候,如果传入的filed少于两个,代码中检验了要反序列化的filed是否溢出,就会出现问题,所以至少需要传入两个,以防止被抛出异常

  3. 最后网上的数据包没有加上EOF标志位,识别不出来数据为row packet,加上就可以

com.mysql.jdbc.BufferRow#getColumnValuerow packet获取数据:

至于为什么加多一行也可以,可能是设置的column count为2,而后续我放了3个field packet,导致虽然在wireshark里面识别成field packet,但在代码里读取的时候当成row packet(我猜的)

Ref

  1. https://xz.aliyun.com/t/8159
  2. https://pyn3rd.github.io/2022/06/06/Make-JDBC-Attacks-Brillian-Again-I/

其他版本区别

8.x < 8.0.20​

  1. 环境搭建

pom.xml:

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
  1. 漏洞分析

区别在于:

调用com.mysql.cj.jdbc.ConnectionImpl#connectOneTryOnly时,使用的是queryInterceptor

向服务器发送一次查询请求:

跟进到拦截器进行执行前操作:

然后利用查询SHOW SESSION STATUS的结果,执行到调用sink点的位置:

数据包显示,去掉了EOF标志也能正常识别,可能是改了协议:

image-20230609093400530

6.x

  1. 环境搭建
1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
  1. 漏洞分析

Interceptors选择的是statementInterceptors,剩下的调用和$5.1.11\leq$没有区别

image-20230609093924329

5.1.10 >=​

区别:

  1. 初始化在调用createNewIO之后,调用时执行的Interceptors中没有设置,所以getConnection之后需要再次执行查询生效:

    image-20230609105243325
image-20230609103901832

8.0.20 <​

官方修复:不读序列化数据了,改成读字符串

image-20230615094043456
Author: Aizlm
Link: https://aizlm.github.io/2023/05/17/JDBC反序列化/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.