<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/13244

            0x00 前言


            關于JAVA的Apache Commons Collections組件反序列漏洞的分析文章已經有很多了,當我看完很多分析文章后,發現JAVA反序列漏洞的一些要點與細節未被詳細描述,還需要繼續分析之后才能更進一步理解并掌握這個漏洞。

            上述的要點與細節包括:

            1. 為什么需要使用JAVA反射機制
            2. 為什么需要利用sun.reflect.annotation.AnnotationInvocationHandler類
            3. 為什么調用TransformedMap類的decorate方法時,參數一的Map對象需要put進"value"與非空的值*
            4. 為什么AnnotationInvocationHandler類的實例化參數一需要為java.lang.annotation.Retention類

            為了方便和我一樣的小白們理解這個漏洞,我將JAVA反序列化漏洞完整過程的分析與調試進行了整理。分析過程中利用的類為TransformedMap與AnnotationInvocationHandler。發現漏洞不是我等小白能力所及,因此本文不以挖掘漏洞的角度來進行分析,而是在已知漏洞存在的情況下分析漏洞。

            0x01 基礎知識


            JAVA序列化與反序列化

            JAVA序列化簡介

            為了分析JAVA的反序列化漏洞,首先需要了解JAVA的序列化與反序列化機制。

            以下內容來自JDK1.6 API文檔中對ObjectOutputStream的說明。

            ObjectOutputStream 將 Java 對象的基本數據類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)對象。通過在流中使用文件可以實現對象的持久存儲。如果流是網絡套接字流,則可以在另一臺主機上或另一個進程中重構對象。

            只能將支持 java.io.Serializable 接口的對象寫入流中。每個 serializable 對象的類都被編碼,編碼內容包括類名和類簽名、對象的字段值和數組值,以及從初始對象中引用的其他所有對象的閉包。

            writeObject 方法用于將對象寫入流中。所有對象(包括 String 和數組)都可以通過 writeObject 寫入。可將多個對象或基元寫入流中。必須使用與寫入對象時相同的類型和順序從相應 ObjectInputstream 中讀回對象。

            即使用ObjectOutputStream.writeObject方法可對實現了Serializable接口的對象進行序列化,序列化后的數據可存儲在文件中,或通過網絡傳輸。

            JAVA反序列化簡介

            以下內容來自JDK1.6 API文檔中對ObjectInputStream的說明。

            ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化。

            ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時,可以為應用程序提供對對象圖形的持久存儲。ObjectInputStream 用于恢復那些以前序列化的對象。其他用途包括使用套接字流在主機之間傳遞對象,或者用于編組和解組遠程通信系統中的實參和形參。

            ObjectInputStream 確保從流創建的圖形中所有對象的類型與 Java 虛擬機中顯示的類相匹配。使用標準機制按需加載類。

            只有支持 java.io.Serializable 或 java.io.Externalizable 接口的對象才能從流讀取。

            readObject 方法用于從流讀取對象。應該使用 Java 的安全強制轉換來獲取所需的類型。在 Java 中,字符串和數組都是對象,所以在序列化期間將其視為對象。讀取時,需要將其強制轉換為期望的類型。

            即使用ObjectInputStream.readObject方法可對序列化的數據進行反序列化。當實現了Serializable接口的對象被反序列化時,該對象的readObject方法會被調用。

            對JAVA基礎類的序列化與反序列化測試

            String實現了Serializable接口,可進行序列化。

            以下測試代碼會對String類的對象進行序列化,將序列化的數據保存在文件中,再從文件讀取序列化的數據進行反序列化。執行上述代碼后,能夠正確輸出原String類的對象的值。

            JAVA序列化數據的magic number

            java.io.ObjectStreamConstants類中定義了STREAM_MAGIC與STREAM_VERSION,查看JDK1.5、1.6、1.7、1.8的ObjectStreamConstants類,STREAM_MAGIC值均為0xaced,STREAM_VERSION值均為5。JDK1.6的源碼中,上述變量的代碼如下。

            #!java
            package java.io;
            
            /**
             * Constants written into the Object Serialization Stream. 
             *
             * @author  unascribed
             * @version %I%, %G%
             * @since JDK 1.1
             */
            public interface ObjectStreamConstants {
            
            /**
             * Magic number that is written to the stream header.
             */
            final static short STREAM_MAGIC = (short)0xaced;
            
            /**
             * Version number that is written to the stream header.
             */
            final static short STREAM_VERSION = 5;
            

            即0xaced為JAVA對象序列化流的魔數,0x0005為JAVA對象序列化的版本號,JAVA對象序列化數據的前4個字節為“AC ED 00 05”。

            查看上一步驟生成的保存了序列化數據的文件,文件內容開頭為“AC ED 00 05”,與上述描述相符。

            對自定義類的序列化與反序列化測試

            以下測試代碼為test.SerializeMyClass類,在其中定義了內部類MyObject。MyObject類實現了Serializable接口,SerializeMyClass類會對MyObject類的對象進行序列化,將序列化的數據保存在文件中,再從文件讀取序列化的數據進行反序列化。

            執行結果如下

            #!bash
            MyObject(String name) tttest
            MyObject-readObject!!!!!!!!!!!!!! tttest
            tttest!  
            

            可以看到MyObject類實現的Serializable接口的readObject方法會被調用,且對象被序列化再反序列化后,對其值不影響。

            生成的保存了序列化數據的文件,文件內容開頭也為“AC ED 00 05”,可以看到文件內容包含了包名與類名、類中包含的變量名稱、類型及變量的值。

            JAVA反射機制

            使用JAVA反射機制調用FileOutputStream類寫文件

            調用FileOutputStream類寫文件時,常用的代碼如下:

            #!java
            FileOutputStream fos = new FileOutputStream("1.txt");
            fos.write("abc".getBytes());
            

            若需要使用JAVA反射機制調用FileOutputStream類寫文件,且只允許調用Class.getMethod與Method.invoke方法,上述代碼需修改為如下形式。

            使用JAVA反射機制調用Runtime類執行程序

            調用Runtime類執行程序時,常用的代碼如下:

            #!java
            Runtime runtime = Runtime.getRuntime();
            runtime.exec("calc");
            

            若需要使用JAVA反射機制調用Runtime類執行程序件,且只允許調用Class.getMethod與Method.invoke方法,上述代碼需修改為如下形式。

            JAVA反射機制與序列化

            當需要操作無法直接訪問的類時,需要使用JAVA的反射機制。即對無法直接訪問的類進行序列化時,需要使用JAVA的反射機制。

            以下測試代碼為testReflection.TestReflection類,與前文中的test.MyObject類不在同一個包中,在TestReflection類中對MyObject類進行序列化時,需要使用JAVA的反射機制。

            以下為執行結果,可以看到使用JAVA的反射機制后,能夠對無法直接訪問的類進行序列化。

            #!bash
            -before newInstance-  
            MyObject(String name) tttest  
            -after newInstance-  
            byteOut.toByteArray().length:71  
            MyObject-readObject!!!!!!!!!!!!!! tttest  
            object:class test.MyObject  
            
            -before newInstance-  
            MyObject(String name) no name-default  
            -after newInstance-  
            byteOut.toByteArray().length:80  
            MyObject-readObject!!!!!!!!!!!!!! no name-default  
            object:class test.MyObject  
            

            0x02 漏洞分析


            使用JAVA反序列化的場景

            breenmachine在“What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common This Vulnerability”中列出了以下會使用JAVA反序列化的場景。

            Java LOVES sending serialized objects all over the place. For example:

            In HTTP requests – Parameters, ViewState, Cookies, you name it.
            RMI – The extensively used Java RMI protocol is 100% based on serialization.
            RMI over HTTP – Many Java thick client web apps use this – again 100% serialized objects.
            JMX – Again, relies on serialized objects being shot over the wire.
            Custom Protocols – Sending an receiving raw Java objects is the norm – which we’ll see in some of the exploits to come.

            可能存在JAVA反序列化漏洞的場景

            JAVA中間件通常通過網絡接收客戶端發送的序列化數據,JAVA中間件在對序列化數據進行反序列化數據時,會調用被序列化對象的readObject方法。如果某個對象的readObject方法中能夠執行任意代碼,那么JAVA中間件在對其進行反序列化時,也會執行對應的代碼。如果能夠找到滿足上述條件的對象進行序列化并發送給JAVA中間件,JAVA中間件也會執行指定的代碼,即存在反序列化漏洞。

            JAVA反序列化漏洞需要滿足兩個條件:

            1. JAVA中件間需要存在客戶端進行序列化時使用的類,否則服務器在進行反序列化時會出現ClassNotFoundException異常;
            2. 客戶端選擇的進行序列化的類在執行代碼時,不會進行任何驗證或限制,會完全按照要求執行。

            利用JAVA反序列化漏洞可以使服務器執行任意代碼,可以直接控制服務器,危害非常大。

            Apache Commons Collections組件說明

            下文中出現的以下類均包含在Apache Commons Collections組件中。

            org.apache.commons.collections.functors.ConstantTransformer
            org.apache.commons.collections.functors.InvokerTransformer
            org.apache.commons.collections.functors.ChainedTransformer
            org.apache.commons.collections.map.TransformedMap
            org.apache.commons.collections.map.AbstractInputCheckedMapDecorator
            org.apache.commons.collections.map.AbstractMapDecorator
            org.apache.commons.collections.set.AbstractSetDecorator
            org.apache.commons.collections.collection.AbstractCollectionDecorator
            org.apache.commons.collections.iterators.AbstractIteratorDecorator
            org.apache.commons.collections.keyvalue.AbstractMapEntryDecorator

            Apache Commons Collections組件原生的jar包為commons-collections-xxx.jar。

            本文中分析的commons-collections-xxx.jar版本為3.2.1,JDK版本為1.6。

            通過對commons-collections-xxx.jar中涉及的代碼進行反編譯,增加輸出或進行調試,可以跟蹤漏洞觸發時的代碼執行情況。

            利用ChainedTransformer執行代碼

            ConstantTransformer類的transform方法

            org.apache.commons.collections.functors.ConstantTransformer類的transform方法會返回構造函數傳入的參數。ConstantTransformer類相關代碼如下。

            #!java
            public class ConstantTransformer implements Transformer, Serializable {
            
                private final Object iConstant;
            
                public ConstantTransformer(Object constantToReturn) {
                    this.iConstant = constantToReturn;
                }
            
                public Object transform(Object input) {
                    return this.iConstant;
                }
                ...
            }
            

            InvokerTransformer類的transform方法

            org.apache.commons.collections.functors.InvokerTransformer類的transform方法可以通過JAVA反射機制執行指定的代碼,能指定所需執行的類、方法及參數,且在transform方法中未進行任何驗證或限制。transform方法中執行的代碼的方法名、參數類型及參數值在InvokerTransformer類的構造函數中指定。InvokerTransformer類相關代碼如下。

            #!java
            public class InvokerTransformer implements Transformer, Serializable {
            
                private final String iMethodName;
                private final Class[] iParamTypes;
                private final Object[] iArgs;
            
                public InvokerTransformer(String methodName, Class[] paramTypes,
                    Object[] args) {
                    this.iMethodName = methodName;
                    this.iParamTypes = paramTypes;
                    this.iArgs = args;
                }       
            
                public Object transform(Object input) {
                    if (input == null)
                        return null;
                    try {
                        Class cls = input.getClass();
                        Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                        return method.invoke(input, this.iArgs);
                    }
                    ...
                }
            }
            

            利用ChainedTransformer執行代碼分析

            以下為利用org.apache.commons.collections.functors.ChainedTransformer類執行任意代碼的示例,當執行最后的“chain.transform(chain);”后,會執行傳入的Transformer數組指定的代碼。在該示例中,會啟動計算器程序。

            ConstantTransformer與InvokerTransformer數組可被轉換為org.apache.commons.collections.functors.ChainedTransformer對象。在ChainedTransformer類的帶參數構造函數中,會將參數中的ConstantTransformer與InvokerTransformer數組保存為this.iTransformers對象。在ChainedTransformer類的transform方法中,會依次調用this.iTransformers對應的ConstantTransformer與InvokerTransformer數組的transform方法,且前一次執行transform方法的返回值object,會作為下一次執行transform方法的參數object。ChainedTransformer類的相關代碼如下。

            #!java
            public class ChainedTransformer implements Transformer, Serializable {
            
                public ChainedTransformer(Transformer[] transformers) {
                    this.iTransformers = transformers;
                }
                ...
                public Object transform(Object object) {
                    for (int i = 0; i < this.iTransformers.length; ++i) {
                        object = this.iTransformers[i].transform(object);
                    }
                    return object;
                }
                ...
            }
            

            對于上述的示例代碼,在執行最后的“chain.transform(chain);”方法時,會首先調用ConstantTransformer.transform方法獲取其構造函數中傳入的類,再依次調用InvokerTransformer.transform方法執行其構造函數中傳入的方法,等價于下面的代碼。

            上述代碼與前文“使用JAVA反射機制調用Runtime類執行程序”中的代碼相同,已經過驗證可以成功執行,能夠調用指定的程序。ChainedTransformer也能夠調用FileOutputStream類進行寫文件操作,相關代碼見前文“使用JAVA反射機制調用FileOutputStream類寫文件”部分。由此可見,利用ChainedTransformer類能夠執行指定的代碼。

            利用TransformedMap類執行代碼

            以下為通過org.apache.commons.collections.map.TransformedMap類執行任意代碼的示例,當執行最后的“localEntry.setValue(null);”后,會執行傳入的Transformer數組指定的代碼。在該示例中,會啟動計算器程序。

            涉及的變量及類型

            上述示例代碼中涉及的變量及類型如下。

            變量 類型
            outerMap org.apache.commons.collections.map.TransformedMap
            set org.apache.commons.collections.map.AbstractInputCheckedMapDecorator$EntrySet
            localIterator org.apache.commons.collections.map.AbstractInputCheckedMapDecorator$EntrySetIterator
            localEntry org.apache.commons.collections.map.AbstractInputCheckedMapDecorator$MapEntry

            org.apache.commons.collections.map.TransformedMap類直接繼承自org.apache.commons.collections.map.AbstractInputCheckedMapDecorator類,間接繼承自java.util.Map類。org.apache.commons.collections.map.TransformedMap類的繼承關系如下。

            org.apache.commons.collections.map.TransformedMap  
             └org.apache.commons.collections.map.AbstractInputCheckedMapDecorator  
              └org.apache.commons.collections.map.AbstractMapDecorator  
               └java.util.Map
            

            調用TransformedMap類的decorate方法

            上述示例中第33行代碼TransformedMap.decorate調用了TransformedMap類的decorate方法。TransformedMap類的decorate方法中創建了TransformedMap對象,以調用decorate方法的參數一map作為參數調用了父類AbstractInputCheckedMapDecorator的構造函數,并將調用decorate方法的參數三valueTransformer保存為this.valueTransformer變量。TransformedMap類相關代碼如下。

            #!java
            public class TransformedMap extends AbstractInputCheckedMapDecorator implements     Serializable {
            
                protected final Transformer keyTransformer;
                protected final Transformer valueTransformer;
            
                public static Map decorate(Map map, Transformer keyTransformer,
                        Transformer valueTransformer) {
                    return new TransformedMap(map, keyTransformer, valueTransformer);
                }
            
                protected TransformedMap(Map map, Transformer keyTransformer,
                        Transformer valueTransformer) {
                    super(map);
                    this.keyTransformer = keyTransformer;
                    this.valueTransformer = valueTransformer;
                }
                ...
            }
            

            在TransformedMap類的父類AbstractInputCheckedMapDecorator的構造函數中,以自身類構造函數的參數為參數調用了父類的構造函數。AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {
                protected AbstractInputCheckedMapDecorator(Map map) {
                    super(map);
                }
                ...
            }
            

            在AbstractInputCheckedMapDecorator類的父類AbstractMapDecorator的構造函數中,將構造函數的參數保存為this.map對象。AbstractMapDecorator類相關代碼如下。

            #!java
            public abstract class AbstractMapDecorator implements Map {
                protected transient Map map;
            
                public AbstractMapDecorator(Map map) {
                    if (map == null) {
                        throw new IllegalArgumentException("Map must not be null");
                    }
                    this.map = map;
                }
                ...
            }
            

            可以看出,上述示例代碼中,第33行代碼調用TransformedMap類的decorate方法時,參數一innerMap被保存為生成的TransformedMap對象的map變量,參數三chain被保存為valueTransformer變量。

            調用AbstractInputCheckedMapDecorator類的entrySet方法

            上述示例中第35行代碼outerMap.entrySet調用了TransformedMap類的父類AbstractInputCheckedMapDecorator的entrySet方法。AbstractInputCheckedMapDecorator類為抽象類,在其entrySet方法中,創建了EntrySet類的對象并返回。在調用EntrySet類的構造函數時,參數二為this,由于AbstractInputCheckedMapDecorator類為抽象類。在上述示例代碼執行時,參數二this即為TransformedMap類的對象outerMap。

            EntrySet類為AbstractInputCheckedMapDecorator類的內部類,在其構造函數中,會將參數二保存為this.parent變量。在上述示例代碼執行時,TransformedMap類的對象outerMap會被保存為EntrySet類的this.parent變量。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {
                protected boolean isSetValueChecking() {
                    return true;
                }
            
                public Set entrySet() {
                    if (isSetValueChecking()) {
                        return new EntrySet(this.map.entrySet(), this);
                    }
                    return this.map.entrySet();
                }
                ...
            
                static class EntrySet extends AbstractSetDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected EntrySet(Set set, AbstractInputCheckedMapDecorator parent) {
                        super(set);
                        this.parent = parent;
                    }
                    ...
                }
            }
            

            調用AbstractInputCheckedMapDecorator$EntrySet類的iterator方法

            上述示例代碼中第37行代碼set.iterator調用了AbstractInputCheckedMapDecorator$EntrySet類的iterator方法。在EntrySet類的iterator方法中,創建了AbstractInputCheckedMapDecorator$EntrySetIterator類的對象并返回,在調用EntrySetIterator類的構造函數時,參數二為this.parent。在上述示例代碼中,this.parent即為TransformedMap類的對象outerMap。

            EntrySetIterator類為AbstractInputCheckedMapDecorator類的內部類,在其構造函數中,會將參數二保存為this.parent變量。在上述示例代碼執行時,TransformedMap類的對象outerMap會被保存為EntrySetIterator類的this.parent變量。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {  
                static class EntrySet extends AbstractSetDecorator {
                    private final AbstractInputCheckedMapDecorator parent;  
            
                    public Iterator iterator() {
                        return new AbstractInputCheckedMapDecorator.EntrySetIterator(
                                this.collection.iterator(), this.parent);
                    }
                    ...
                }
            
                static class EntrySetIterator extends AbstractIteratorDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected EntrySetIterator(Iterator iterator,
                            AbstractInputCheckedMapDecorator parent) {
                        super(iterator);
                        this.parent = parent;
                    }
                    ...
                }
                ...
            }
            

            調用AbstractInputCheckedMapDecorator$EntrySetIterator類的next方法

            上述示例代碼中第39行代碼localIterator.next調用了AbstractInputCheckedMapDecorator$EntrySetIterator類的next方法。在EntrySetIterator類的next方法中,創建了AbstractInputCheckedMapDecorator$MapEntry類的對象并返回,在調用MapEntry類的構造函數時,參數二為this.parent。在上述示例代碼中,this.parent即為TransformedMap類的對象outerMap。

            MapEntry類為AbstractInputCheckedMapDecorator類的內部類,在其構造函數中,會將參數二保存為this.parent變量。在上述示例代碼執行時,TransformedMap類的對象outerMap會被保存為MapEntry類的this.parent變量。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {  
            
                static class EntrySetIterator extends AbstractIteratorDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    public Object next() {
                        Map.Entry entry = (Map.Entry) this.iterator.next();
                        return new AbstractInputCheckedMapDecorator.MapEntry(entry,
                                this.parent);
                    }
                    ...
                }
                ...
                static class MapEntry extends AbstractMapEntryDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected MapEntry(Map.Entry entry,
                            AbstractInputCheckedMapDecorator parent) {
                        super(entry);
                        this.parent = parent;
                    }
                    ...
                }
            }
            

            調用AbstractInputCheckedMapDecorator$MapEntry類的setValue方法

            上述示例代碼中第43行代碼localEntry.setValue調用了AbstractInputCheckedMapDecorator$MapEntry類的setValue方法。在MapEntry類的setValue方法中,調用了this.parent的checkSetValue方法。在上述示例代碼中,MapEntry類的this.parent即為TransformedMap類的對象outerMap,因此會調用TransformedMap類的checkSetValue方法。AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {  
                static class MapEntry extends AbstractMapEntryDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    public Object setValue(Object value) {
                        value = this.parent.checkSetValue(value);
                        return this.entry.setValue(value);
                    }
                    ...
                }
            }
            

            在TransformedMap類的checkSetValue方法中,會調用this.valueTransformer.transform方法。在前文的示例代碼中,TransformedMap類的對象outerMap的this.valueTransformer變量對應ChainedTransformer類對象chain。前文“利用ChainedTransformer執行代碼分析”部分已經說明,調用ChainedTransformer類的transform方法時,會執行其在構造時傳入的ConstantTransformer與InvokerTransformer數組中指定的方法。TransformedMap類相關代碼如下。

            #!java
            public class TransformedMap extends AbstractInputCheckedMapDecorator implements
                Serializable {
                protected Object checkSetValue(Object value) {
                    return this.valueTransformer.transform(value);
                }
                ...
            }
            

            綜上所述,上述示例代碼最后的“localEntry.setValue(null);”時,會執行ConstantTransformer與InvokerTransformer數組指定的方法。

            漏洞觸發時的調用過程

            上述漏洞在觸發時的完整調用過程如下。

            //調用TransformedMap類的decorate方法  
            TransformedMap.decorate  
            AbstractMapDecorator.AbstractMapDecorator  
            AbstractInputCheckedMapDecorator.AbstractInputCheckedMapDecorator  
            TransformedMap.TransformedMap  
            
            //調用AbstractInputCheckedMapDecorator類的entrySet方法  
            AbstractInputCheckedMapDecorator.entrySet  
            TransformedMap.isSetValueChecking  
            AbstractInputCheckedMapDecorator$EntrySet.EntrySet  
            
            //調用AbstractInputCheckedMapDecorator$EntrySet類的iterator方法  
            AbstractInputCheckedMapDecorator$EntrySet.iterator  
            AbstractInputCheckedMapDecorator$EntrySetIterator.EntrySetIterator  
            
            //調用AbstractInputCheckedMapDecorator$EntrySetIterator類的next方法  
            AbstractInputCheckedMapDecorator$EntrySetIterator.next  
            AbstractMapEntryDecorator.AbstractMapEntryDecorator  
            AbstractInputCheckedMapDecorator$MapEntry.MapEntry  
            
            //調用AbstractInputCheckedMapDecorator$MapEntry類的setValue方法  
            AbstractInputCheckedMapDecorator$MapEntry.setValue  
            TransformedMap.checkSetValue  
            ChainedTransformer.transform  
            InvokerTransformer.transform
            

            AbstractInputCheckedMapDecorator$MapEntry對象的鍵值對

            在確定了利用TransformedMap類可以執行代碼以后,再來關注上述示例代碼中調用最后的“localEntry.setValue”之前的localEntry的鍵值對。之所以需要關注localEntry的鍵值對,是因為在通過AnnotationInvocationHandler類執行代碼時,這是一個重要的變量。

            從上述示例代碼第35行“outerMap.entrySet”開始分析,之前的步驟不再重復。

            上述示例中第35行代碼outerMap.entrySet調用了TransformedMap類的父類AbstractInputCheckedMapDecorator的entrySet方法。在AbstractInputCheckedMapDecorator類的entrySet方法中,創建了EntrySet類的對象并返回。在調用EntrySet類的構造函數時,參數一為this.map.entrySet()。在上述示例代碼中,AbstractInputCheckedMapDecorator類的this.map.entrySet()對應Map對象innerMap的entrySet()。

            在AbstractInputCheckedMapDecorator$EntrySet類的構造函數中,會將參數一set作為參數調用父類org.apache.commons.collections.set.AbstractSetDecorator的構造函數。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {
                protected boolean isSetValueChecking() {
                    return true;
                }
            
                public Set entrySet() {
                    if (isSetValueChecking()) {
                        return new EntrySet(this.map.entrySet(), this);
                    }
                    return this.map.entrySet();
                }
                ...
            
                static class EntrySet extends AbstractSetDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected EntrySet(Set set, AbstractInputCheckedMapDecorator parent) {
                        super(set);
                        this.parent = parent;
                    }
                    ...
                }
            }
            

            在AbstractSetDecorator類的構造函數中,會將參數一set作為參數調用父類org.apache.commons.collections.collection.AbstractCollectionDecorator的構造函數。

            AbstractSetDecorator類相關代碼如下。

            #!java
            public abstract class AbstractSetDecorator extends AbstractCollectionDecorator
                    implements Set {
                protected AbstractSetDecorator(Set set) {
                    super(set);
                }
                ...
            }
            

            在AbstractCollectionDecorator類的構造函數中,會將參數一coll保存為this.collection變量,即AbstractCollectionDecorator類的this.collection變量保存了示例代碼中Map對象innerMap的entrySet()。

            AbstractCollectionDecorator類相關代碼如下。

            #!java
            public abstract class AbstractCollectionDecorator implements Collection {
                protected Collection collection;
            
                protected AbstractCollectionDecorator(Collection coll) {
                    if (coll == null) {
                        throw new IllegalArgumentException("Collection must not be null");
                    }
                    this.collection = coll;
                }
                ...
            }
            

            上述示例代碼中第37行代碼set.iterator調用了AbstractInputCheckedMapDecorator$EntrySet類的iterator方法。在EntrySet類的iterator方法中,創建了AbstractInputCheckedMapDecorator$EntrySetIterator類的對象并返回,在調用EntrySetIterator類的構造函數時,參數一為this.collection.iterator()。在上述示例代碼中,this.collection.iterator()即為Map對象innerMap的entrySet().iterator()。

            在AbstractInputCheckedMapDecorator$EntrySetIterator類的構造函數中,會將參數一iterator作為參數調用父類org.apache.commons.collections.iterators.AbstractIteratorDecorator的構造函數。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {  
                static class EntrySet extends AbstractSetDecorator {
                    private final AbstractInputCheckedMapDecorator parent;  
            
                    public Iterator iterator() {
                        return new AbstractInputCheckedMapDecorator.EntrySetIterator(
                                this.collection.iterator(), this.parent);
                    }
                    ...
                }
            
                static class EntrySetIterator extends AbstractIteratorDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected EntrySetIterator(Iterator iterator,
                            AbstractInputCheckedMapDecorator parent) {
                        super(iterator);
                        this.parent = parent;
                    }
                    ...
                }
                ...
            }
            

            在AbstractIteratorDecorator類的構造函數中,會將參數一iterator保存為this.iterator變量,即AbstractIteratorDecorator類的this.iterator變量保存了示例代碼中Map對象innerMap的entrySet().iterator()。

            AbstractIteratorDecorator類相關代碼如下。

            #!java
            public class AbstractIteratorDecorator implements Iterator {
                protected final Iterator iterator;
            
                public AbstractIteratorDecorator(Iterator iterator) {
                    if (iterator == null) {
                        throw new IllegalArgumentException("Iterator must not be null");
                    }
                    this.iterator = iterator;
                }
                ...
            }
            

            上述示例代碼中第39行代碼localIterator.next調用了AbstractInputCheckedMapDecorator$EntrySetIterator類的next方法。在EntrySetIterator類的next方法中,創建了AbstractInputCheckedMapDecorator$MapEntry類的對象并返回,在調用MapEntry類的構造函數時,參數一為this.iterator.next()。在上述示例代碼中,this.iterator.next()即為Map對象innerMap的entrySet().iterator().next(),即示例代碼中第30行通過innerMap.put添加的鍵值對。

            在AbstractInputCheckedMapDecorator$EntrySet類的構造函數中,會將參數一entry作為參數調用父類org.apache.commons.collections.keyvalue.AbstractMapEntryDecorator的構造函數。

            AbstractInputCheckedMapDecorator類相關代碼如下。

            #!java
            abstract class AbstractInputCheckedMapDecorator extends AbstractMapDecorator {  
            
                static class EntrySetIterator extends AbstractIteratorDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    public Object next() {
                        Map.Entry entry = (Map.Entry) this.iterator.next();
                        return new AbstractInputCheckedMapDecorator.MapEntry(entry,
                                this.parent);
                    }
                    ...
                }
                ...
                static class MapEntry extends AbstractMapEntryDecorator {
                    private final AbstractInputCheckedMapDecorator parent;
            
                    protected MapEntry(Map.Entry entry,
                            AbstractInputCheckedMapDecorator parent) {
                        super(entry);
                        this.parent = parent;
                    }
                    ...
                }
            }
            

            在AbstractMapEntryDecorator類的構造函數中,會將參數一entry保存為this.entry變量,在getKey與getValue方法會分別返回this.entry.getKey()與this.entry.getValue()。

            AbstractMapEntryDecorator類相關代碼如下。

            #!java
            public abstract class AbstractMapEntryDecorator implements Map.Entry, KeyValue {
                protected final Map.Entry entry;
            
                public AbstractMapEntryDecorator(Map.Entry entry) {
                    if (entry == null) {
                        throw new IllegalArgumentException("Map Entry must not be null");
                    }
                    this.entry = entry;
                }
            
                public Object getKey() {
                    return this.entry.getKey();
                }
            
                public Object getValue() {
                    return this.entry.getValue();
                }
                ...
            }
            

            綜上所述,在示例代碼中執行第39行localIterator.next后,執行localEntry.getKey()與localEntry.getValue()可獲取示例代碼中第30行通過innerMap.put添加的鍵值對。

            利用TransformedMap與AnnotationInvocationHandler類執行代碼

            已知TransformedMap類為Map類的子類,為了觸發JAVA反序列化漏洞,需要找到某個類提供了方法接收Map對象,且在readObject方法中會調用Map對象的Entry的setValue方法。

            sun.reflect.annotation.AnnotationInvocationHandler類滿足上述的要求。sun.reflect.annotation.AnnotationInvocationHandler類為JRE中原生的類,不需要第三方支持。

            以下為通過TransformedMap與AnnotationInvocationHandler類執行任意代碼的示例,當執行第57行的“ois.readObject();”后,會執行傳入的Transformer數組指定的代碼。在該示例中,會啟動計算器程序。

            sun.reflect.annotation.AnnotationInvocationHandler類無法直接訪問,因此在構造需要序列化的對象時,需要使用JAVA反射機制。

            在上述觸發漏洞的示例代碼中,會調用AnnotationInvocationHandler類的帶參數構造函數與反序列化時會被調用的readObject函數。

            AnnotationInvocationHandler類的重要的變量及方法如下。

            #!java
            1.  class AnnotationInvocationHandler implements InvocationHandler, Serializable {
            2.      private final Class type;
            3.      private final Map<String, ObjectmemberValues;
            4.      ...
            5.
            6.      AnnotationInvocationHandler(Class paramClass, Map<String, ObjectparamMap) {
            7.          this.type = paramClass;
            8.          this.memberValues = paramMap;
            9.      }
            10.     ...
            11.
            12.     private void readObject(ObjectInputStream paramObjectInputStream)
            13.             throws IOException, ClassNotFoundException {
            14.         paramObjectInputStream.defaultReadObject();
            15.         AnnotationType localAnnotationType = null;
            16.         try {
            17.             localAnnotationType = AnnotationType.getInstance(this.type);
            18.         } catch (IllegalArgumentException localIllegalArgumentException) {
            19.             return;
            20.         }
            21.         Map localMap = localAnnotationType.memberTypes();
            22.         Iterator localIterator = this.memberValues.entrySet().iterator();
            23.         while (localIterator.hasNext()) {
            24.             Map.Entry localEntry = (Map.Entry) localIterator.next();
            25.             String str = (String) localEntry.getKey();
            26.             Class localClass = (Class) localMap.get(str);
            27.             if (localClass != null) {
            28.                 Object localObject = localEntry.getValue();
            29.                 if ((!(localClass.isInstance(localObject)))
            30.                         && (!(localObject instanceof ExceptionProxy)))
            31.                     localEntry.setValue(new AnnotationTypeMismatchExceptionProxy(
            32.                                     localObject.getClass() + "[" + localObject
            33.                                             + "]")
            34.                                     .setMember((Method) localAnnotationType
            35.                                             .members().get(str)));
            36.             }
            37.         }
            38.     }
            

            示例代碼中第43行執行newInstance方法時,對應AnnotationInvocationHandler類代碼的第6行的帶參數構造方法。示例代碼中第43行執行newInstance方法構造AnnotationInvocationHandler對象時,參數一為java.lang.annotation.Retention.class,參數二為TransformedMap類的對象outerMap。因此AnnotationInvocationHandler類代碼中構造函數中保存的this.type對應java.lang.annotation.Retention.class,this.memberValues對應示例代碼中的outerMap。

            當AnnotationInvocationHandler類的readObject方法執行時,過程如下。

            綜上所述,在利用TransformedMap與AnnotationInvocationHandler類觸發JAVA反序列化漏洞時,有以下幾點應滿足條件。

            利用TransformedMap與AnnotationInvocationHandler類觸發JAVA反序列化漏洞

            綜合前文的分析,利用TransformedMap與AnnotationInvocationHandler類觸發JAVA反序列化漏洞的大致步驟如下。

            簡而言之,當攻擊者將構造好的包含攻擊代碼序列化數據發送給使用了Apache Commons Collections組件的JAVA中間件時,JAVA中間件在對其進行反序列化操作時,會觸發反序列化漏洞,執行攻擊者指定的任意代碼。

            不同JAVA中間件的JAVA反序列化漏洞利用與防護分析,之后再繼續。

            參考資料

            What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common This Vulnerability http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
            common-collections中Java反序列化漏洞導致的RCE原理分析 WooYun知識庫 http://drops.wooyun.org/papers/10467
            Commons Collections Java反序列化漏洞深入分析 - 博客 - 騰訊安全應急響應中心 http://security.tencent.com/index.php/blog/msg/97
            JAVA Apache-CommonsCollections 序列化漏洞分析以及漏洞高級利用 隨風'S Blog http://www.iswin.org/2015/11/13/Apache-CommonsCollections-Deserialized-Vulnerability/
            Java反序列化漏洞技術分析 天融信阿爾法實驗室 http://blog.topsec.com.cn/ad_lab/java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90/
            Java反序列化漏洞之Weblogic、Jboss利用教程及exp - HereSecurity http://www.heresec.com/index.php/archives/127/
            Java反序列化漏洞之weblogic本地利用實現篇 - FreeBuf_COM 關注黑客與極客 http://www.freebuf.com/vuls/90802.html
            Lib之過?Java反序列化漏洞通用利用分析 - Cnlouds的個人空間 - 開源中國社區 http://my.oschina.net/u/1188877/blog/529611
            WebLogic之Java反序列化漏洞利用實現二進制文件上傳和命令執行 WooYun知識庫 http://drops.wooyun.org/papers/11690

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线