Hibernate链分析
Hibernate
简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。
前置知识
一个奇怪小知识,就是在java中的Class.this和this的区别
class Outer{
String data = "Out!";
public class Inner{
String data = "In!";
public String getOuterData(){
return Outer.this.data; // will return "Out!"
}
}
}
第一次见这么写接口实现的
//ValueHolder
public interface DeferredInitializer<T> {
T initialize();
}
//TypedValue
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
this.initTransients();
}
private void initTransients() {
this.hashcode = new ValueHolder(new ValueHolder.DeferredInitializer<Integer>() {
public Integer initialize() {
return TypedValue.this.value == null ? 0 : TypedValue.this.type.getHashCode(TypedValue.this.value);
}
});
}
链分析
/**
*
* org.hibernate.property.access.spi.GetterMethodImpl.get()
* org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue()
* org.hibernate.type.ComponentType.getPropertyValue(C)
* org.hibernate.type.ComponentType.getHashCode()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.engine.spi.TypedValue$1.initialize()
* org.hibernate.internal.util.ValueHolder.getValue()
* org.hibernate.engine.spi.TypedValue.hashCode()
*
*
* Requires:
* - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only)
*
* @author mbechler
*/
先看序列化返回数据的类型,是HashMap,看一下内容的存储结构
两对键值对key和value都是TypedValue类,我们又知道在HashMap反序列化的时候会自动对key执行hashCode操作,所以我们就从TypedValue的hashCode方法开始跟入
//org.hibernate.engine.spi.TypedValue
public int hashCode() {
return (Integer)this.hashcode.getValue();
}
变量内的hashcode为ValueHolder类,这里的ValueHolder和TypedValue就是对其中的value进行了一定的包装,方便我们获取其类型和属性,我们鸡血跟入ValueHolder.getValue
//ValueHolder
public ValueHolder(DeferredInitializer<T> valueInitializer) {
this.valueInitializer = valueInitializer;
}
public T getValue() {
if (this.value == null) {
this.value = this.valueInitializer.initialize();
}
return this.value;
}
执行了this.valueInitializer.initialize,这里的valueInitializer是在构造函数中传入的,我们继续跟入
private void initTransients() {
this.hashcode = new ValueHolder(new ValueHolder.DeferredInitializer<Integer>() {
public Integer initialize() {
return TypedValue.this.value == null ? 0 : TypedValue.this.type.getHashCode(TypedValue.this.value);
}
});
}
进入到了TypedValue的initTransients中对ValueHolder的DeferredInitializer的实现中,调用了TypedValue.type.getHashCode(TypedValue.this.value),这里value就是构造了恶意字节码的TemplateImpl对象了,跟入
public int getHashCode(Object x) {
int result = 17;
for(int i = 0; i < this.propertySpan; ++i) {
Object y = this.getPropertyValue(x, i);
result *= 37;
if (y != null) {
result += this.propertyTypes[i].getHashCode(y);
}
}
return result;
}
//org.hibernate.type.ComponentType
public int getHashCode(Object x) {
int result = 17;
for(int i = 0; i < this.propertySpan; ++i) {
Object y = this.getPropertyValue(x, i);
result *= 37;
if (y != null) {
result += this.propertyTypes[i].getHashCode(y);
}
}
return result;
}
public Object getPropertyValue(Object component, int i) throws HibernateException {
return component instanceof Object[] ? ((Object[])((Object[])component))[i] : this.componentTuplizer.getPropertyValue(component, i);
}
调用到this.componentTuplizer.getPropertyValue(恶意字节码对象,i)
//org.hibernate.tuple.component.AbstractComponentTuplizer
public Object getPropertyValue(Object component, int i) throws HibernateException {
return this.getters[i].get(component);
}
public Object get(Object owner) {
try {
return this.getterMethod.invoke(owner);
} catch (InvocationTargetException var3) {
throw new PropertyAccessException(var3, "Exception occurred inside", false, this.containerClass, this.propertyName);
} catch (IllegalAccessException var4) {
throw new PropertyAccessException(var4, "IllegalAccessException occurred while calling", false, this.containerClass, this.propertyName);
} catch (IllegalArgumentException var5) {
LOG.illegalPropertyGetterArgument(this.containerClass.getName(), this.propertyName);
throw new PropertyAccessException(var5, "IllegalArgumentException occurred calling", false, this.containerClass, this.propertyName);
}
}
继续调用this.getters[i].get(恶意字节码对象)
,最终调用到this.getterMethod.invoke(owner)
这里的getterMethod就是我们先前构造的getOutputProperties方法,传入恶意字节码对象,完成RCE