背景

上周BlackHat Europe 2019的议题《New Exploit Technique In Java Deserialization Attack》中提到了一个通过注入JDBC URL实现反序列化攻击的场景,简单分析一下。

分析

当java应用使用MySQL Connector/J(官方的JDBC驱动,本文基于其8.0+版本)连接mysql时会导致潜在的反序列化攻击风险,JDBC URL的格式如下:protocol//[hosts]/[database]?properties,具体可看mysql官方文档,示例:jdbc:mysql://localhost:3306/test?useSSL=true

其中,protocol、host、database都比较好理解,URL中的properties可以设定MySQL Connector/J连接mysql服务器的具体方式,关于properties的官方文档地址,其中和本文相关的连接属性有两个,分别是autoDeserializequeryInterceptors,前者是设定MySQL Connector/J是否反序列化BLOB类型的数据,后者是拦截器,在查询执行时触发,由com.mysql.cj.protocol.a.NativeProtocol#sendQueryPacket方法源码可知,会在执行查询语句前后分别调用拦截器的preProcess和postProcess方法。

接下来定位下反序列化的触发点,在mysql-connector-java组件下全局搜索关键字“.readObject()”,定位到com.mysql.cj.jdbc.result.ResultSetImpl类中的getObject(int columnIndex)方法,部分核心代码如下:

public Object getObject(int columnIndex) throws SQLException {
……
case BLOB:
byte[] data = getBytes(columnIndex);
if (this.connection.getPropertySet().getBooleanProperty(PropertyDefinitions.PNAME_autoDeserialize).getValue()) {
Object obj = data;
// Serialized object?
try {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
ObjectInputStream objIn = new ObjectInputStream(bytesIn);
obj = objIn.readObject();
}
}
}

变量data即为mysql返回结果集,当JDBC URL中设定属性autoDeserialize为true时,会对类型为bit、binary以及blob的数据进行反序列化,如何触发getObject(int columnIndex)方法的调用呢?议题中给出的调用链如下:

> com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#preProcess/postProcess
> com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#populateMapWithSessionStatusValues
> com.mysql.cj.jdbc.util.ResultSetUtil#resultSetToMap
> com.mysql.cj.jdbc.result.ResultSetImpl#getObject

ServerStatusDiffInterceptor即为此前提到过的拦截器,在JDBC URL中设定属性queryInterceptors为ServerStatusDiffInterceptor时,执行查询语句会调用拦截器的preProcess和postProcess方法,进而通过上述调用链最终调用getObject(int columnIndex)方法。

实际利用还有一个问题,最终调用getObject方法的对象是数据库返回的结果集,由populateMapWithSessionStatusValues方法可知:

try {
toPopulate.clear(); stmt = this.connection.createStatement();
rs = stmt.executeQuery("SHOW SESSION STATUS");
ResultSetUtil.resultSetToMap(toPopulate, rs);
}

这个结果集是执行SQL语句“SHOW SESSION STATUS”后数据库返回的值,SQL语句“SHOW SESSION STATUS”返回当前数据库连接的状态值,实际是读取系统表INFORMATION_SCHEMA.SESSION_VARIABLES的值,也可能是PERFORMANCE_SCHEMA.SESSION_VARIABLES(Mysql版本差异导致)。但是mysql中INFORMATION_SCHEMA和PERFORMANCE_SCHEMA都是不允许被修改的,所以需要想办法操纵返回的数据。

利用条件

1.本质上还是Java原生的反序列化利用,所以需要环境中有可用的Gadget;

2.需要能伪造相关系统表的数据,将“SHOW SESSION STATUS”的执行结果设置为我们精心构造的反序列化数据,或者基于mysql连接协议,自定义返回数据,后面有时间的时候会写写这块儿;

3.可控的JDBC URL;

最新文章

  1. 数据库优化案例——————某市中心医院HIS系统
  2. OpenStack 企业私有云的若干需求(2):自动扩展(Auto-scaling) 支持
  3. css块级元素,内联元素,内联块状元素
  4. NGUI之添加响应函数
  5. 判断CAD图纸版本
  6. spring依赖注入单元测试:expected single matching bean but found 2
  7. 转 scrollLeft,scrollWidth,clientWidth,offsetWidth之完全详解
  8. [转] 多线程下变量-gcc原子操作 __sync_fetch_and_add等
  9. dns-prefetch—DNS预解析技术
  10. 2015第23周四HTML特殊字符显示问题
  11. A Simple Problem with Integers(100棵树状数组)
  12. Drupal设置首页默认内容
  13. postman简单教程-环境变量,全局变量的设置及作用
  14. CTSC2017总结
  15. Linux 驱动——Button驱动4(fasync)异步通知
  16. 【docker 入门 - 01】- Docker 在 Centos7 上安装与测试
  17. Python基础-文件操作(七)
  18. 多进程模块 multiprocessing
  19. CentOS7.2调整Mysql数据库最大连接数
  20. DB通用类:MySQL通用类

热门文章

  1. Arduino 基于 ESP8266 配置WIFI模块
  2. LVM弹性硬盘
  3. Hadoop MapReduce常用输入输出格式
  4. jsp页面使用EL表达式 使用Jstl标签库中的标签,需要引入jstl.jar和standard.jar
  5. vue-cli从2升级到3报错error 404 Not Found: @wry/context@^0.4.0
  6. TypeError: Cannot read property '_t' of undefined (VUE + ElementUI + i18n)
  7. JavaScript实战实例剖析——(激励倒计时日历)
  8. CentOS 7 安装 dnsmasq 服务 实现内网DNS
  9. Zookeeper 应用实现-配置中心
  10. 4k图片爬取+中文乱码