C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。许多开源项目如Hibernate、Spring等都在使用它。虽然之前有接触过C3P0,但并没有深入了解。比如,在学习二次反序列化时,发现
WrapperConnectionPoolDataSource
就是C3P0的一部分。
在项目中引入C3P0的依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
URLClassLoader是初学者必须掌握的一环。下面给出完整的exp,然后逐步进行分析。
(代码段略)
首先,我们来看序列化的过程。进入
PoolBackedDataSourceBase
类,查看
writeObject
方法。该方法尝试对当前对象的
connectionPoolDataSource
属性进行序列化。如果无法序列化,则在catch块中使用
ReferenceIndirector.indirectForm
方法处理
connectionPoolDataSource
属性后再进行序列化操作。接下来跟进
ReferenceIndirector.indirectForm
方法。
(图片信息略)
接下来看反序列化的操作。首先获取反序列化后的对象,然后判断这个对象
o
是否实现了
IndirectlySerialized
接口。在
ReferenceIndirector
的内部类
ReferenceSerialized
中实现了这个接口,因此通过判断,调用了
o
的
getObject
方法。
(图片信息略)
跟进
getObject
方法,发现其中居然还有lookup。但是我们的目标不是这里,而且这里的lookup并不重要。
(图片信息略)
跟进
ReferenceableUtils.referenceToObject
,由于
ref
是在序列化时可以控制的参数,那么
fClassName
自然也是可以控制的属性。下面就调用了URLClassLoader实例化我们的远程恶意类。
(图片信息略)
如果没有网络访问,并且是fastjson或jackson环境,可以使用这个Gadget。这条链以前见过,就是学习二次反序列化时的C3P0那条链。因此这里就不再详细讲解,可以去看看我讲二次反序列化的那篇文章。
在fastjson、jackson环境中同样可用。
(代码段略)
首先,
JndiRefConnectionPoolDataSource
类中有属性
jndiname
及其
setter
方法。其
setter
方法会调用内部的
JndiRefForwardingDataSource
对象的
setJndiName
方法,改变
JndiRefForwardingDataSource#jndiname
的值。漏洞点在
setLoginTimeout
处。我们追踪进去,经过几次
setLoginTimeout
来到这。
(图片信息略)
进入
dereference
,获取
jndiName
,然后调用了lookup,达到jndi的效果。
(图片信息略)