欢迎来到代码驿站!

JAVA代码

当前位置:首页 > 软件编程 > JAVA代码

Java JDBC导致的反序列化攻击原理解析

时间:2020-10-31 19:29:41|栏目:JAVA代码|点击:

这篇文章主要介绍了Java JDBC导致的反序列化攻击原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

背景

上周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的官方文档地址,其中和本文相关的连接属性有两个,分别是autoDeserialize和queryInterceptors,前者是设定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

上一篇:java中concat()方法的使用说明

栏    目:JAVA代码

下一篇:Java NIO Path接口和Files类配合操作文件的实例

本文标题:Java JDBC导致的反序列化攻击原理解析

本文地址:http://www.codeinn.net/misctech/17836.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有