CommonsCollections (CC1) basics of Java deserialization


Preface

      This article includes: some basic knowledge concepts of Java Deserialization CommonsCollections (CC1).


1. Basic introduction and environment

    1.Introduction to Apache Commons Collections

      Apache Commons Collections is a very commonly used tool library in Java application development. It adds many powerful data structures, simplifies the development of Java applications, and has become a recognized standard for Java to process collection data. Many common applications such as Weblogic, WebSphere, Jboss, Jenkins, etc. all use the Apache Commons Collections tool library. When a deserialization vulnerability occurs in the tool library, these applications are also affected. This is why the deserialization vulnerability is so serious. reason.

    2. Principle of vulnerability

      Apache Commons Collections provides a Transformer class. The function of this interface is to convert one object into another object.
      Then the entire utilization chain needs to focus on this class.

  • invokeTransformer: Returns an object through reflection.
  • ChainedTransformer: Connect transformers into a chain, and transform an object through each transformer in the chain in turn.
  • ConstantTransformer: Convert an object into a constant and return it.

    3. Environment version of this article

      The IDEA version is: 2021.1.3
      The jdk version is 8u65, because the CC1 exploit chain was fixed in the 8u71 version. Download address: https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
      Maven version: 3.6.3, download link: https://archive.apache.org/dist/maven /maven-3/3.6.3/binaries/The
      version of CommonsCollections in this article is 3.2.1. It can be between 3.1-3.21.

<dependencies>
    <!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.1</version>
    </dependency>
</dependencies>

      To facilitate debugging, the java source code needs to be added. The download address is: https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4.

    4.Building process

     1) Download the source code of the corresponding version of openjdk. and extract it into a folder.
Insert image description here
Insert image description here
     2) Unzip src.zip in the jdk1.8.0_65 folder. Then copy the sun folder of jdk-af660750b2f4\src\share\classes in the downloaded openjdk to the decompressed src folder.
Insert image description here

Insert image description here
Insert image description here
     3) IDEA creates a maven project, and Project SDK selects the path to the jdk8u65 you downloaded. Then write the name of your project and create the storage path in the next step.
Insert image description here
     4) After creation, select ProjectStructure project structure.
Insert image description here
     5) Select SDKs, click Sourcepath, add src, and finally apply and save.
Insert image description here
     6) Then add commons collections 3.2.1 version to the pom.xml file, download the resources directly or right-click to reload the project to download the resources.
Insert image description here
Insert image description here

2. Basic learning

   1. How to execute the command

     1) Normal command execution in JAVA.

public class CC1 {
    
    
    public static void main(String[] atgs) throws Exception
    {
    
    
        // 1.先弹个计算器
        Runtime.getRuntime().exec("calc");
    }
}

Insert image description here
     2) Use a common reflection to execute the command.

import java.lang.reflect.Method;

public class CC1 {
    
    
    public static void main(String[] atgs) throws Exception
    {
    
    
//        // 1.先弹个计算器
//        Runtime.getRuntime().exec("calc");


        // 2.写一个普通的反射
        Runtime r = Runtime.getRuntime();
        // 获取Runtime的class
        Class c = Runtime.class;
        // 获取Runtime的exec方法
        Method execMethod = c.getMethod("exec",String.class);
        // 调用exec方法
        execMethod.invoke(r,"calc");
    }
}

Insert image description here

   2. Introduction to the classes involved in the CC1 chain

     1) The Transformer class is a set of customized functional classes in Commons Collections. The function of the Transformer class is to receive an object and then call the transform method to perform some operations on the object.

public interface Transformer {
    
    
    public Object transform(Object input);
}

     2) InvokerTransformer is also a class that implements the Transformer interface, and it can execute any method. When creating an InvokerTransformer object, you need to pass in three parameters. The first is the name of the method you want to execute, the second is the parameter type of the parameters required by this method, and the third is the specific parameters in this method; when calling When using the transform method in the InvokerTransformer class, the method we want to execute will be executed. So which object is the method specifically? It is passed in through the parameters in the transform method. Next, let’s look at the code. The first is the construction method:

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    
    
    super();
    iMethodName = methodName;
    iParamTypes = paramTypes;
    iArgs = args;
}

      It's just an assignment of three parameters. Next, let's look at its callback transform method.

public Object transform(Object input) {
    
    
    if (input == null) {
    
    
        return null;
 }
 try {
    
    
     Class cls = input.getClass();
     Method method = cls.getMethod(iMethodName, iParamTypes);
     return method.invoke(input, iArgs);}
    catch (NoSuchMethodException ex) {
    
    
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' does not exist");} 
    catch (IllegalAccessException ex) {
    
    
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} 
    catch (InvocationTargetException ex) {
    
    
        throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}
}

      In this way, it can execute the iMethodName method of the input object. The principle is actually quite simple. It is to use reflection to obtain this method first, and then execute this method in the input object. 3) The TransformedMap class encapsulates a decorate method
     . It is used to modify the standard data structure Map in Java. When a new element is added to the modified Map, it will execute a callback function; this callback is not a callback function in the traditional sense, but is equivalent to executing The transform method in an object requires that the class of the object implements the Transformer interface. Referring to the code below, we can see that keyTransformer is a callback for processing the Key of new elements, and valueTransformer is a callback for processing the value of new elements. When we add a new element to outerMap, it will call the transform method in keyTransformer or valueTransformer.

Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, keyTransformer, valueTransformer);

     4) ConstantTransformer is also a class that implements the Transformer interface. This class is very simple. It has a constructor with parameters, and the parameter type is an object. When you pass in an object, it will be used in the transform method. This object is returned. That is to return the passed in object constantToReturn in the transform method.

public ConstantTransformer(Object constantToReturn) {
    
    
    super();
    iConstant = constantToReturn;
}
public Object transform(Object input) {
    
    
    return iConstant;
}

     5) As mentioned before, there are two classes: ConstantTransformer and InvokerTransformer. One can return an object of a class, and the other can execute methods in the object. So can we try to execute the exec method in the Runtime class? Obviously, we also need a class to string these two together so that the object returned by the ConstantTransformer class can be used as a parameter to enter the transform method of the InvokerTransformer class. This is enough. At this time, we need to take out our ChainedTransformer class. The ChainedTransformer class is also a class that implements the Transformer interface. It strings together multiple internal classes that implement the Transformer interface, and uses the result returned by the previous callback function transform as the parameter of the next callback function transform. Pass in, the code is as follows, a very simple logic, which is to constantly adjust the transform

public ChainedTransformer(Transformer[] transformers) {
    
    
    super();
    iTransformers = transformers;
}
public Object transform(Object object) {
    
    
    for (int i = 0; i < iTransformers.length; i++) {
    
    
        object = iTransformers[i].transform(object);
        }
    return object;
}

Insert image description here

Guess you like

Origin blog.csdn.net/qq_44029310/article/details/127624206