diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 59e2902..0000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Java CI - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Build with Maven - run: mvn -B package --file pom.xml - - - name: Upload artifact - uses: actions/upload-artifact@v1.0.0 - with: - # Artifact name - name: ysoserial - # Directory containing files to upload - path: /home/runner/work/ysoserial/ysoserial/target/ diff --git a/src/test/java/ysoserial/CiTest.java b/src/test/java/ysoserial/CiTest.java index d658d73..6b4615a 100644 --- a/src/test/java/ysoserial/CiTest.java +++ b/src/test/java/ysoserial/CiTest.java @@ -2,10 +2,21 @@ package ysoserial; import org.junit.Test; +import java.util.Map; +import java.util.TreeMap; + public class CiTest { @Test public void test() { - System.out.println("System.getProperties(): " + System.getProperties()); - System.out.println("System.getenv(): " + System.getenv()); + for (Map.Entry e : new TreeMap(System.getProperties()).entrySet()) { + System.out.println("System property " + e.getKey() + " : " + e.getValue()); + } + for (Map.Entry e : new TreeMap(System.getenv()).entrySet()) { + System.out.println("System env " + e.getKey() + " : " + e.getValue()); + } + } + + public static void main(String[] args) { + new CiTest().test(); } } diff --git a/src/test/java/ysoserial/test/payloads/PayloadsTest.java b/src/test/java/ysoserial/test/payloads/PayloadsTest.java index f5cbf8c..e2e59cd 100644 --- a/src/test/java/ysoserial/test/payloads/PayloadsTest.java +++ b/src/test/java/ysoserial/test/payloads/PayloadsTest.java @@ -5,9 +5,11 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.MalformedURLException; import java.net.URL; -import java.net.URLClassLoader; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; @@ -33,6 +35,7 @@ import ysoserial.payloads.annotation.Dependencies; import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.ClassFiles; import ysoserial.test.util.Logging; +import ysoserial.test.util.OpenURLClassLoader; import ysoserial.test.util.PayloadListener; import ysoserial.test.util.StdIoRedirection; @@ -71,7 +74,7 @@ public class PayloadsTest { } - public static void testPayload ( final Class> payloadClass, final Class[] addlClassesForClassLoader ) + public static void testPayload(final Class> payloadClass, final Class[] addlClassesForClassLoader) throws Exception { System.out.println("Testing payload: " + payloadClass.getName()); @@ -140,11 +143,8 @@ public class PayloadsTest { } if (ex != null) throw ex; } - } - - private static Callable makeSerializeCallable ( final Class> payloadClass, final String command ) { return new Callable() { @@ -158,7 +158,6 @@ public class PayloadsTest { }; } - private static Callable makeDeserializeCallable ( PayloadTest t, final Class[] addlClassesForClassLoader, final String[] deps, final byte[] serialized, final Class customDeserializer ) { return new Callable() { @@ -169,14 +168,12 @@ public class PayloadsTest { }; } - private static boolean checkPrecondition ( Class> pc, String precondition ) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method precondMethod = pc.getMethod(precondition); return (Boolean) precondMethod.invoke(null); } - private static String[] buildDeps ( final Class> payloadClass ) throws Exception { String[] baseDeps; if ( DynamicDependencies.class.isAssignableFrom(payloadClass) ) { @@ -193,9 +190,52 @@ public class PayloadsTest { return baseDeps; } - - static Object deserializeWithDependencies ( byte[] serialized, final String[] dependencies, final Class[] classDependencies, final Class customDeserializer ) + static Object deserializeWithDependencies(byte[] serialized, final String[] dependencies, final Class[] classDependencies, final Class customDeserializer) throws Exception { + URL[] urls = getDependencyUrls(dependencies); + + Map addlClasses = new HashMap(); + + for ( Class clazz : classDependencies ) { + byte[] classAsBytes = ClassFiles.classAsBytes(clazz); + addlClasses.put(clazz.getName(), classAsBytes); + } + addlClasses.put(Deserializer.class.getName(), ClassFiles.classAsBytes(Deserializer.class)); + + if (customDeserializer != null) { + try { + Method method = customDeserializer.getMethod("getExtraDependencies"); + for (Class extra : (Class[]) method.invoke(null)) { + addlClasses.put(extra.getName(), ClassFiles.classAsBytes(extra)); + } + } catch (NoSuchMethodException e) {} + + addlClasses.put(customDeserializer.getName(), ClassFiles.classAsBytes(customDeserializer)); + } + + OpenURLClassLoader isolatedClassLoader = new OpenURLClassLoader(urls, null); + for (Map.Entry e : addlClasses.entrySet()) { + isolatedClassLoader.defineNewClass(e.getKey(), e.getValue()); + } + + Class deserializerClass = isolatedClassLoader.loadClass(customDeserializer != null ? customDeserializer.getName() : Deserializer.class.getName()); + Callable deserializer = (Callable) deserializerClass.getConstructors()[0].newInstance(serialized); + + // set CCL for Clojure https://groups.google.com/forum/#!topic/clojure/F3ERon6Fye0 + return callWithContextClassLoader(isolatedClassLoader, deserializer); + } + + private static Object callWithContextClassLoader(ClassLoader classLoader, Callable callable) throws Exception { + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(classLoader); + try { + return callable.call(); + } finally { + Thread.currentThread().setContextClassLoader(ccl); + } + } + + private static URL[] getDependencyUrls(String[] dependencies) throws MalformedURLException { File[] jars = dependencies.length > 0 ? Maven.configureResolver() .withMavenCentralRepo(true) @@ -206,46 +246,7 @@ public class PayloadsTest { for ( int i = 0; i < jars.length; i++ ) { urls[ i ] = jars[ i ].toURI().toURL(); } - - URLClassLoader isolatedClassLoader = new URLClassLoader(urls, null) { - - { - for ( Class clazz : classDependencies ) { - byte[] classAsBytes = ClassFiles.classAsBytes(clazz); - defineClass(clazz.getName(), classAsBytes, 0, classAsBytes.length); - } - byte[] deserializerClassBytes = ClassFiles.classAsBytes(Deserializer.class); - defineClass(Deserializer.class.getName(), deserializerClassBytes, 0, deserializerClassBytes.length); - - if ( customDeserializer != null ) { - - try { - Method method = customDeserializer.getMethod("getExtraDependencies"); - for ( Class extra : (Class[])method.invoke(null)) { - deserializerClassBytes = ClassFiles.classAsBytes(extra); - defineClass(extra.getName(), deserializerClassBytes, 0, deserializerClassBytes.length); - } - } catch ( NoSuchMethodException e ) { } - - deserializerClassBytes = ClassFiles.classAsBytes(customDeserializer); - defineClass(customDeserializer.getName(), deserializerClassBytes, 0, deserializerClassBytes.length); - } - - } - }; - - Class deserializerClass = isolatedClassLoader.loadClass(customDeserializer != null ? customDeserializer.getName() : Deserializer.class.getName()); - Callable deserializer = (Callable) deserializerClass.getConstructors()[ 0 ].newInstance(serialized); - - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); - try { - // set CCL for Clojure https://groups.google.com/forum/#!topic/clojure/F3ERon6Fye0 - Thread.currentThread().setContextClassLoader(isolatedClassLoader); - final Object obj = deserializer.call(); - return obj; - } finally { - Thread.currentThread().setContextClassLoader(ccl); - } + return urls; } public static void main(String[] args) throws IOException { diff --git a/src/test/java/ysoserial/test/util/OpenURLClassLoader.java b/src/test/java/ysoserial/test/util/OpenURLClassLoader.java new file mode 100644 index 0000000..e2b8b2f --- /dev/null +++ b/src/test/java/ysoserial/test/util/OpenURLClassLoader.java @@ -0,0 +1,14 @@ +package ysoserial.test.util; + +import java.net.URL; +import java.net.URLClassLoader; + +public class OpenURLClassLoader extends URLClassLoader { + public OpenURLClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public Class defineNewClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } +} diff --git a/src/test/java/ysoserial/test/util/PayloadListener.java b/src/test/java/ysoserial/test/util/PayloadListener.java index 051f277..31c6ed4 100644 --- a/src/test/java/ysoserial/test/util/PayloadListener.java +++ b/src/test/java/ysoserial/test/util/PayloadListener.java @@ -3,10 +3,10 @@ package ysoserial.test.util; import org.junit.runner.Description; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunListener; +import ysoserial.Strings; import java.io.ByteArrayOutputStream; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class PayloadListener extends RunListener { public enum Status { @@ -25,7 +25,7 @@ public class PayloadListener extends RunListener { @Override public void testStarted(Description description) throws Exception { - System.out.println(getPayload(description.getDisplayName()) + ": STARTED"); +// System.out.println(getPayload(description.getDisplayName()) + ": STARTED"); statuses.put(description, Status.SUCCESS); @@ -46,8 +46,34 @@ public class PayloadListener extends RunListener { StdIoRedirection.restoreStreams(); Status status = statuses.get(description); - System.out.println(getPayload(description.getDisplayName()) + ": " + status); - if (status == Status.FAILURE) System.err.println(outs.get(description).toString()); + String payload = getPayload(description.getDisplayName()); + String out = outs.get(description).toString(); + + Map props = new HashMap(); + props.put("payload", payload); + props.put("status", status.toString()); +// props.put("out", out); + for (String k : Arrays.asList("java.version", "java.vendor", "java.vm.version", "java.runtime.version", "os.arch", "os.name", "os.version")) { + props.put(k, System.getProperty(k)); + } + + List pairs = new ArrayList(); + for (Map.Entry e : props.entrySet()) { + StringBuilder sb = new StringBuilder(); + sb.append("\"") + .append(e.getKey().replace("\\", "\\\\").replace("\"", "\\\"")) + .append("\"") + .append(": ") + .append("\"") + .append(e.getValue().replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t").replace("\b", "\\b")) + .append("\""); + pairs.add(sb.toString()); + } + + String obj = "{" + Strings.join(pairs, ", ", "", "") + "}"; + + System.out.println(obj); +// System.out.println(payload + ": " + status); } @Override diff --git a/src/test/java/ysoserial/test/util/StdIoRedirection.java b/src/test/java/ysoserial/test/util/StdIoRedirection.java index 09e742a..e11be89 100644 --- a/src/test/java/ysoserial/test/util/StdIoRedirection.java +++ b/src/test/java/ysoserial/test/util/StdIoRedirection.java @@ -5,6 +5,7 @@ import javassist.util.proxy.ProxyFactory; import java.io.OutputStream; import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /*