01

漏洞概述

该漏洞是Black Hat Europe 2019的议题《New Exploit Technique In Java Deserialization Attack》。

只要用户能控制客户端的JDBC连接串,在连接阶段即可触发该漏洞,无需继续执行SQL语句。

mysql-connector-java是Java进行JDBC执行的依赖包,支持在Java代码中对数据库进行连接与SQL语句执行等。

02

影响范围

mysql-connector-java-5.1.18 ~ 5.1.40

mysql-connector-java-6.x

mysql-connector-java-8.0.7以上

03

修复建议

建议在项目开发时,不允许MySQL连接串被用户控制。

如果存在功能需求(如DolphinScheduler),建议将mysql-connector-java-5版本升级到5.1.40以上,6、8版本升级到最新版本。

04

漏洞分析

该漏洞在mysql-connector-java-5、6、8的某些版本中都存在,只不过利用链不同,下面首先分析mysql-connect-java-5版本。

 mysql-connect-java-5版本 

注:本次分析利用的环境为mysql-connector-java-5.1.29 。

mysql-connect-java-5版本中利用的是detectCustomCollations的触发方式,触发点在com.mysql.jdbc.ConnectionImpl的buildCollationMapping方法中。

可以看到,只要MySQL版本大于4,且getDetectCustomCollations( )为true即可。之后会再次判断服务器的MySQL版本是否在5以上,接着调用Util.resultSetToMap( ) 。

然后会调用传入参数result的getObject( )方法,跟进getObject( )方法。

注:此处直接Ctrl+鼠标左键不能直接进入调用getObject( )方法的地方,只会跳到interface类的方法中,真正的getObject( )方法在该interface类的impl类中。

补充说明:传入的result对象是stmt.executeQuery("SHOW COLLATION")的返回值,stmt对象是通过getMetadataSafeStatement( )获取的,跟进该方法,可以看到声明stmt的方法为createStatement( ) 。在这个方法中可以看到,该链实际返回的stmt对象是StatementImpl类创建出的对象,因此原来的stmt.executeQuery("SHOW COLLATION")中执行的executeQuery( )方法,是在StatementImpl类中重写的executeQuery( )方法,即传入的result对象是executeQuery( )方法执行后的返回值。

而在executeQuery("SHOW COLLATION")方法中,返回的result对象是通过this.results = locallyScopedConn.execSQL( )赋值的,locallyScopedConn对象是this.connetion赋值的,所以需要找到this.connetion的赋值处。存在于StatementImpl的构造方法中,传入的是MySqlConnection的对象。根据刚刚创建stmt的流程,传入的是getLoadBalanceSafeProxy( )的返回结果。根据结果,最后定位在ConnectionImple类的execSQL( )方法,返回的是ResultSetInternalMethods类的对象,但ResultSetInternalMethods是一个接口类,所以最终的实例化对象必然是其实现类,而ResultSetImpl恰好是该类的实现类,所以继续向下跟踪,必然会找到返回该类的实例化对象或是其子类的实例化对象的语句。最后,执行完成后返回的对象是JDBC4ResultSet类的对象,且该类继承了ResultSetImpl类。

综上所述,在Util.resultSetToMap( )中调用的getObject( )方法如果在JDBC4ResultSet类中未被重写的话,会调用父类的getObject( )方法。经过审计代码,发现JDBC4ResultSet类只重写了如下的重载方法,所以此处应该调用父类的getObject( )方法。

public T getObject ( int columnIndex, Class type ) throws SQLException

在跟进该方法时,代码如下:

可以看出,此处获取了查询结果,且对于结果集的每一列进行了getSQLType判断。当此处的返回值为-2时,会判断该字段是否为二进制串,且是否为BLOB类型,接着会判断是否开启了反序列化,以及是否为Java反序列化开头的二进制数据,最终可以实现readObject( )方法进行反序列化。

也就是说,只要字段2或字段3搭载了序列化数据,在其处理过程中就会进行反序列化,从而执行恶意代码。

POC构造

想要复现该漏洞,需要准备一个带有恶意对象的数据库表,由于要在SHOW COLLATION执行处触发,所以带有恶意对象的表应该在系统表里(即INFORMATION_SCHEMA COLLATIONS表),当mysql_jdbc_connect对恶意数据库进行连接请求时会触发反序列化。

但是修改系统表可能会引入其他未知问题。针对这种情况,可以采用其他方法。

这里要提到mysql_jdbc_connect的工作原理。mysql_jdbc_connect是通过与数据库端口进行私有协议(即MySQL协议)来交互的,那么可以伪造一个MySQL服务端,让mysql_jdbc_connect连接虚假服务端,将恶意序列化对象插入返回数据中,由mysql_jdbc_connect进行反序列化执行即可。

想要构造这个数据包,需要了解MySQL私有协议的交互流程。这里抓取正常的本地loop报文,简单分析交互流程。

握手报文如下:

连接请求如下:

认证响应如下:

流程大致如上图,后续每执行一次SQL相关操作,就会通过该协议与数据库进行一次交互。

上文提到,触发点在连接时数据库执行SHOW COLLATION的地方,所以重点关注SHOW COLLATION的请求与响应。

SHOW COLLATION请求如下:

SHOW COLLATION响应如下:

使用python构造一个恶意的MySQL服务端,用于监听客户端的连接(握手报文构造与上面一致即可),SHOW COLLATION响应代码如下:

注:1、由于connector 5版本的getObject( )方法需要用到第三列数据,所以构造响应时需要至少构造三列响应数据;

2、需要FLAGS大于128、来源表不为空,否则会被当成Text 。

复现结果

启动模拟MySQL监听后,使用Java作为客户端发出连接请求。

执行getConnection( )方法时计算器弹出。

 mysql-connect-java-8版本 

注:本次分析利用的环境为mysql-connector-java-8.0.14 。

8版本connector的触发点与5版本的触发点不同。

前文提到,5版本的触发点是detectCustomCollations为true,且触发位置在com.mysql.jdbc.ConnectionImpl的buildCollationMapping方法中。

而8版本则使用ServerStatusDiffInterceptor的触发方式,这也是原议题中给出的环境与触发方式。触发点位于com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor类的populateMapWithSessionStatusValues方法中。

进入该方法,会调用到ResultSetUtil类的resultSetToMap方法。

再进入该方法,会调用ResultSet的派生类重写的getObject( )方法,此处的ResultSet对象是createStatement( )创建的对象执行executeQuery("SHOW SESSION STATUS")后返回的结果,通过跟踪,最终定位到真正调用getObject( )方法的是com.mysql.cj.jdbc.result.ResultSetImpl类的getObject( )方法。

之后和5版本的判断基本相同,判断是否为二进制,判断是否为BLOB类型的数据,最后再判断自动反序列化是否开启。

从ServerStatusDiffInterceptor到反序列化这条链已经弄通,接下来分析如何在JDBC连接的时候,调用ServerStatusDiffInterceptor类的populateMapWithSessionStatusValues方法。

首先看到ServerStatusDiffInterceptor类,它是一个拦截器,并且实现了QueryInterceptor接口。

补充说明:Connector/J拦截器类,仅在8.0.7版本以上使用。

拦截器是一种软件设计模式,提供了一种透明的方式来扩展或修改程序的某些方面,类似于用户出口,无需重新编译。使用Connector/J,通过更新连接字符串以引用实例化的不同组的拦截器类,可以启用和禁用拦截器。

可以在queryInterceptors中指定实现com.mysql.cj.interceptors.QueryInterceptor接口的类的标准名称。在这种拦截器类中,可能会更改或增强某些类型的语句所完成的处理,例如自动检查内存缓存服务器中的查询数据,重写慢速查询,记录有关语句的执行信息或请求路由到远程服务器。

在JDBC的连接串中可以控制拦截器的连接属性,如:

jdbc:mysql://your-ip:3306/xxx?queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor

当拦截器在JDBC连接串中使用时,其作用是在执行SQL语句查询前后,通过一些特定操作来影响查询结果。所以要触发queryInterceptors则需要能执行SQL查询语句,而在getConnection过程中,会触发SET NAMES utf、set autocommit=1一类的请求,因此会触发配置的queryInterceptors 。

从代码层面也可以看出这套逻辑:

1、在初始化过程中,会调用ConnectImpl类的setAutoCommit( )方法,该方法会执行SET autocommit语句。

2、执行execSQL( )方法会调用到sendQueryString( ),之后会调用sendQueryPacket( )方法。

3、在sendQueryPacket( )方法中会判断是否设置了queryInterceptors,如果设置了拦截器,则通过反射调用其preProcess( )方法。

4、最后从ServerStatusDiffInterceptor的preProcess( )方法中调用populateMapWithSessionStatusValues( )方法,进入利用链。

POC构造

与5版本类似,只有两个地方不同:

1、JDBC连接串的URL

在5版本中需要设置detectCustomCollations为true;而在8版本中,需要设置queryInterceptors,连接串如下:

jdbc:mysql://127.0.0.1:3306/vaethink?queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

2、恶意响应的构造

在5版本中,根据查询语句“SHOW COLLATION”的Query包进行恶意响应构造;而在8版本中,需要对“SHOW SESSION STATUS”的Query包进行恶意响应构造。

模拟的MySQL服务端只需要增加对show session status包的响应即可。下附网上的POC代码,其中get_payload_content方法中获取的是可弹出计算器的序列化对象。

复现结果

启动模拟MySQL监听后,使用Java作为客户端发出连接请求。

计算器弹出,使用的是该POC的默认序列化对象,即弹出计算器的序列化对象。

05

参考链接

https://xz.aliyun.com/t/8159

https://blog.csdn.net/fnmsd/article/details/106232092

安博通,可视化网络安全技术创新者威胁情报【漏洞预警】Apache Shiro绕过权限漏洞(CVE-2020-17510)【漏洞预警】ZenTaoPMS 文件上传漏洞(CNVD-C-2020-121325)【漏洞预警】Apache Kylin未授权配置泄露漏洞(CVE-2020-13937)

点击,了解安博通

checkbox未赋值时获取value是on_【漏洞分析】关于mysqlconnectorjava连接时的反序列化...相关推荐

  1. checkbox未赋值时获取value是on_C语言中的指针——指针的赋值和指向

    文/Edward 当我们将一个指针变量定义好之后,接下来需要考虑的问题就是如何来使用这个指针变量了.前面学习普通变量的时候,我们知道,一个变量的操作其实就是分成读和写两个步骤.而指针变量在平时使用的时 ...

  2. gettype获取类名_在TypeScript中运行时获取对象的类名

    在TypeScript中运行时获取对象的类名 是否可以使用typescript在运行时获取对象的类/类型名称? class MyClass{} var instance = new MyClass() ...

  3. el如何获取复选框的值_element ui 表格提交时获取所有选中的checkbox的数据

    设定此属性@selection-change="changeFun",意思是每次勾选的时候都会触发这个事件 //复选框状态改变 changeFun(val) { this.mult ...

  4. 如何获取注解中的值_如何在运行时利用注解信息

    注解( annontation )是 Java 1.5 之后引入的一个为程序添加元数据的功能.注解本身并不是魔法,只是在代码里添加了描述代码自身的信息,至于如何理解和使用这些信息,则需要专门的解析代码 ...

  5. android获取wifi别名,android-连接WIFI时获取SSID

    android-连接WIFI时获取SSID 当我的android设备连接到WIFI时,我试图获取WIFI网络的SSID. 我已经注册了一个BroadcastReceiver,用于监听wifiInfo. ...

  6. java 运行时获取泛型真实类型

    前情提要 本文章用于运行时获取泛型的具体类型,有一些情况下可以获取到真实类型,有一些情况下获取不到的情况. Class 类的两个方法 /*** Returns the {@code Class} re ...

  7. checkbox选中和不选中 jqu_jQuery解决checkbox未选中不提交值的问题

    Loading... W3C最新规定,当checkbox未选中,post不会将值提交到服务器,这就出现了一个变量未初始化的问题,看网上有很多朋友增加隐藏表单的方式解决,如果有多个checkbox的话, ...

  8. 【MATLAB】基本绘图 ( 句柄值 | 对象句柄值获取 | 创建对象时获取句柄值 | 函数获取句柄值 | 获取 / 设置 对象属性 | 获取对象属性 )

    文章目录 一.对象句柄值获取 1.句柄值 2.创建对象时获取句柄值 3.函数获取句柄值 4.获取 / 设置 对象属性 二.获取对象属性 1.获取 线 对象属性 2.获取 坐标轴 对象属性 一.对象句柄 ...

  9. 笔记本有线网卡未识别无法获取IP地址

    一直以来都是使用WIFI连接路由器上网,今天闲着没事干找了根网线连接到路由器,发现无法上网,显示未识别网络. 1,用另外一台笔记本尝试一切正常,初步排除路由器和网线出现问题. 2,卸载有线网卡驱动,重 ...

  10. JQuery 判断checkbox是否选中,checkbox全选,获取checkbox选中值

    2019独角兽企业重金招聘Python工程师标准>>> JQuery是一个非常容易上手的框架,但是有很多东西需要我们深入学习的. 判断checkbox是否被选中网上有选多种写法,这里 ...

最新文章

  1. LeetCode 289. Game of Life--Java,Python解法
  2. PXE启动芯片出错代码表、初始化/引导/载入Bootstrap错误代码
  3. Spring 3整合Quartz 2实现定时任务三:动态暂停 恢复 修改和删除任务
  4. STM32技术文档里面的I / O Level FT具体含义
  5. 【终极方法】This method must return a result of type boolean
  6. 基于HTML5 的人脸识别活体认证
  7. Hbase Rowkey设计原则
  8. 《Algorithms》Comparable 实现冒泡排序
  9. 晒晒自己写的C++小程序(初学,书上的题目)
  10. 银行技术岗笔试计算机基础知识点,想去银行技术岗,考试都考啥?
  11. 西北大学计算机转专业,2021年西北大学大一新生转专业及入学考试相关规定
  12. 【Cocos Creator 实战】01 - 如何做一款简单的拼图游戏
  13. #51CTO学院四周年# 感谢51CTO学院让我走出迷茫
  14. STM32 烧录程序后上电不工作,但调试模式下可正常工作的解决办法
  15. 【电源设计】06正激式开关电源
  16. NOIP2016·洛谷·天天爱跑步
  17. 一阶拟合算法C(六轴)
  18. Vue 新手学习笔记:vue-element-admin 之按钮级权限管控
  19. sqoop 导数据从 mysql 到 hdfs,load 进 hive
  20. python将一个组数分成几个相同元素的数组,末位少了不补齐

热门文章

  1. postfix和dovecot架设邮件服务器的一些记录1
  2. 详解 Spring 3.0 基于 Annotation 的依赖注入实现(转)
  3. CentOS TinyProxy http(s)上网代理及置代理上网的方法
  4. 项目中的文件夹与tomcat/webapp中manager文件夹重名
  5. lhgcoreDialogPlugin v3.5.2 使用点滴
  6. 37.MySQL 优化总结
  7. 146.PHP $_SERVER['SCRIPT_FILENAME'] 与 __FILE__ 的区别
  8. 1.Chrome开发者工具不完全指南(一、基础功能篇)
  9. html中表格table的内容居中显示
  10. php 基础 自动类型转换