diff --git a/src/main/java/ysoserial/PayloadTest.java b/src/main/java/ysoserial/PayloadTest.java new file mode 100644 index 0000000..ba21154 --- /dev/null +++ b/src/main/java/ysoserial/PayloadTest.java @@ -0,0 +1,24 @@ +/** + * © 2016 AgNO3 Gmbh & Co. KG + * All right reserved. + * + * Created: 05.03.2016 by mbechler + */ +package ysoserial; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author mbechler + * + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface PayloadTest { + + String skip() default ""; + + String precondition() default ""; + + String harness() default ""; +} diff --git a/src/main/java/ysoserial/payloads/Jdk7u21.java b/src/main/java/ysoserial/payloads/Jdk7u21.java index 398a098..1645a3b 100755 --- a/src/main/java/ysoserial/payloads/Jdk7u21.java +++ b/src/main/java/ysoserial/payloads/Jdk7u21.java @@ -6,6 +6,7 @@ import java.util.LinkedHashSet; import javax.xml.transform.Templates; +import ysoserial.PayloadTest; import ysoserial.payloads.annotation.Dependencies; import ysoserial.payloads.util.Gadgets; import ysoserial.payloads.util.PayloadRunner; @@ -52,6 +53,7 @@ LinkedHashSet.readObject() @SuppressWarnings({ "rawtypes", "unchecked" }) @Dependencies() +@PayloadTest ( precondition = "isApplicableJavaVersion") public class Jdk7u21 implements ObjectPayload { public Object getObject(final String command) throws Exception { @@ -77,6 +79,21 @@ public class Jdk7u21 implements ObjectPayload { return set; } + + public static boolean isApplicableJavaVersion() { + String property = System.getProperties().getProperty("java.version"); + if ( property == null ) { + return false; + } + String parts[] = property.split("\\.|_|-");; + int major = Integer.parseInt(parts[1]); + int minor = Integer.parseInt(parts[2]); + int update = Integer.parseInt(parts[3]); + if ( major < 7 || (major == 7 && update <= 21) ) { + return true; + } + return false; + } public static void main(final String[] args) throws Exception { PayloadRunner.run(Jdk7u21.class, args); diff --git a/src/test/java/ysoserial/CustomTest.java b/src/test/java/ysoserial/CustomTest.java new file mode 100644 index 0000000..e85a4d3 --- /dev/null +++ b/src/test/java/ysoserial/CustomTest.java @@ -0,0 +1,16 @@ +/** + * © 2016 AgNO3 Gmbh & Co. KG + * All right reserved. + * + * Created: 05.03.2016 by mbechler + */ +package ysoserial; + + +/** + * @author mbechler + * + */ +public interface CustomTest extends Runnable { + +} diff --git a/src/test/java/ysoserial/WrappedTest.java b/src/test/java/ysoserial/WrappedTest.java new file mode 100644 index 0000000..55b226f --- /dev/null +++ b/src/test/java/ysoserial/WrappedTest.java @@ -0,0 +1,23 @@ +/** + * © 2016 AgNO3 Gmbh & Co. KG + * All right reserved. + * + * Created: 05.03.2016 by mbechler + */ +package ysoserial; + +import java.util.concurrent.Callable; + +/** + * @author mbechler + * + */ +public interface WrappedTest { + + /** + * @param innerCallable + * @return a wrapped callable + */ + Callable createCallable ( Callable innerCallable ); + +} diff --git a/src/test/java/ysoserial/payloads/PayloadsTest.java b/src/test/java/ysoserial/payloads/PayloadsTest.java index 93dc79e..9f68565 100644 --- a/src/test/java/ysoserial/payloads/PayloadsTest.java +++ b/src/test/java/ysoserial/payloads/PayloadsTest.java @@ -3,6 +3,8 @@ package ysoserial.payloads; import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET; import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; @@ -12,6 +14,7 @@ import java.util.concurrent.Callable; import org.hamcrest.CoreMatchers; import org.jboss.shrinkwrap.resolver.api.maven.Maven; import org.junit.Assert; +import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ProvideSecurityManager; @@ -19,9 +22,12 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import ysoserial.CustomTest; import ysoserial.Deserializer; +import ysoserial.PayloadTest; import ysoserial.Serializer; import ysoserial.Throwables; +import ysoserial.WrappedTest; import ysoserial.payloads.TestHarnessTest.ExecMockPayload; import ysoserial.payloads.TestHarnessTest.NoopMockPayload; import ysoserial.payloads.annotation.Dependencies; @@ -62,21 +68,37 @@ public class PayloadsTest { public static void testPayload(final Class> payloadClass, final Class[] addlClassesForClassLoader) throws Exception { final String command = "hostname"; final String[] deps = buildDeps(payloadClass); + + PayloadTest t = payloadClass.getAnnotation(PayloadTest.class); + + if ( t != null ) { + if ( !t.skip().isEmpty()) { + Assume.assumeTrue(t.skip(), false); + } + + if ( !t.precondition().isEmpty()) { + Assume.assumeTrue("Precondition", checkPrecondition(payloadClass, t.precondition())); + } + } + + Object wrapper = null; + if ( t != null && !t.harness().isEmpty() ) { + wrapper = Class.forName(t.harness()).newInstance(); + + if ( wrapper instanceof CustomTest ) { + ( (CustomTest) wrapper ).run(); + return; + } + } + ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager(); - final byte[] serialized = sm.wrap(new Callable(){ - public byte[] call() throws Exception { - ObjectPayload payload = payloadClass.newInstance(); - final Object f = payload.getObject(command); - return Serializer.serialize(f); - }}); - + final byte[] serialized = sm.wrap(makeSerializeCallable(payloadClass, command)); try { - Object deserialized = sm.wrap(new Callable(){ - public Object call() throws Exception { - return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader); - } - }); - + Callable callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized); + if ( wrapper instanceof WrappedTest ){ + callable = ((WrappedTest)wrapper).createCallable(callable); + } + Object deserialized = sm.wrap(callable); Assert.fail(ASSERT_MESSAGE); // should never get here } catch (Throwable e) { // hopefully everything will reliably nest our ExecException @@ -87,6 +109,41 @@ public class PayloadsTest { Assert.assertEquals(Arrays.asList(command), sm.getCmds()); } + /** + * @param payloadClass + * @param command + * @return + */ + private static Callable makeSerializeCallable ( final Class> payloadClass, final String command ) { + return new Callable(){ + public byte[] call() throws Exception { + ObjectPayload payload = payloadClass.newInstance(); + final Object f = payload.getObject(command); + return Serializer.serialize(f); + }}; + } + + /** + * @param t + * @param addlClassesForClassLoader + * @param deps + * @param serialized + * @return + */ + private static Callable makeDeserializeCallable ( PayloadTest t, final Class[] addlClassesForClassLoader, final String[] deps, final byte[] serialized ) { + return new Callable(){ + public Object call() throws Exception { + return deserializeWithDependencies(serialized, deps, addlClassesForClassLoader); + } + }; + } + + + private static boolean checkPrecondition ( Class> pc, String precondition ) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + Method precondMethod = pc.getMethod(precondition); + return (Boolean) precondMethod.invoke(null); + } + /** * @param payloadClass * @return