我們會在本文中詳細介紹四個在去年被修復的舊漏洞:
CVE-2022-38108;
CVE-2022-36957;
CVE-2022-36958;
CVE-2022-36964;
CVE-2022-38108這個漏洞已經在這篇博客文章中提到了。
簡單來說,幾個SolarWinds服務通過RabbitMQ實例相互通信,該實例可通過端口5671/TCP訪問。雖然訪問它需要憑據,但是高權限用戶可以通過SolarWinds Orion平台提取這些憑據,攻擊者利用CVE-2023-33225,它允許低權限用戶提取這些憑證。
該漏洞針對的是SolarWinds信息服務。為了向信息服務發送AMQP消息,必須將消息的Routing-Key設置為SwisPubSub,RoutingKey就是路由規則,消息對應的隊列。
AMQP消息中的Routing-Key
現在,讓我們來驗證SolarWinds是如何處理這些消息的,可以從EasyNetQ.Consumer.HandleBasicDeliver方法開始:
在[1]處,代碼檢索AMQP消息的屬性,這些屬性由發送消息的攻擊者控制。
在[2]處,它創建了一個執行上下文,其中包含AMQP消息屬性和消息正文。
在[3]處,它執行一個任務來使用消息。
這就需要Consume方法。
在[1]處,EasyNetQ.DefaultMessageSerializationStrategy.DeserializeMessage被調用,它接受輸入的消息屬性和消息正文。調用名為DeSerialize的方法並返回type類型的輸出,作為輸入,它從消息中接受Type屬性。
我們可以通過AMQP消息屬性控制messageType類型!
在[2]處,它調用BytesToMessage,同時接受攻擊者控制的類型和輸入的消息正文。
在[1]處,消息正文被解碼為UTF-8字符串。它應該包含JSON格式的數據。在[2]處,執行反序列化。我們控制目標類型和序列化負載。在[3]處,可以看到TypeNameHandling反序列化設置被設置為Auto。
現在,我們需要遠超需要實現的遠程代碼。要做到這一點,我們必鬚髮送一個AMQP消息,其中Type屬性設置為危險類型。
通過AMQP屬性控制反序列化類型
在消息正文中,我們必須傳播相應的JSON.NETgadget(有潛在可以被利用的代碼片段)。本文使用了ysosserial.net中的一個簡單的WindowsPrincipalgadget,它是內部存儲的BinaryFormattergadget的橋樑,JSON反序列化後,RCE將通過底層BinaryFormatter反序列化來實現。
這樣,就可以通過遠程執行惡意代碼來控制目標系統的漏洞!
CVE-2022-36957在之前的漏洞中,我們能夠通過AMQP屬性完全控制目標反序列化類型。當發現這樣的漏洞時,我們需要知道合法消息是什麼樣子?我們經常檢查在典型產品操作過程中反序列化的類型。
我們很快意識到SolarWinds只發送一種類型的信息,即SolarWinds.MessageBus.Models.Indication。
現在我們分析一下這種類型:在[1]和[2]處,我們可以看到兩個類型為SolarWinds.MessageBus.Models.PropertyBag的公共成員。
在[1]處,您可以看到所討論的類的定義,SolarWinds.MessageBus.Models.PropertyBag。
在[2]處,為該類註冊了一個自定義轉換器SolarWinds.MessageBus.Models.PropertyBagJsonConverter。它實現了ReadJson方法,該方法將在反序列化過程中調用。
在[1]處,代碼遍歷JSON屬性;在[2]處,檢索JSON值並將其轉換為jobobject類型;在[3]處,根據存儲在t鍵中的值檢索Type;在[4]處,存儲在v鍵中的對像被反序列化,此時我們再次控制目標反序列化類型。
你可以看到,我們再次控制了反序列化類型,該類型通過JSON鍵傳播,序列化的有效負載通過v鍵傳播。
現在,我們可以獲取任何屬性,例如:IndicationId。然後,我們需要:
1.將t鍵的值設置為惡意類型的名稱。
2.在v鍵的值中放入惡意序列化的有效負載。
由於JSON反序列化設置被設置為TypeNameHandling.Auto。現在,讓我們看一下上面描述的第一個漏洞,CVE-2022-38108,通過將目標反序列化類型硬編碼到SolarWinds.MessageBus.Models.Indication來修復。畢竟,這是唯一需要反序列化的合法類型。
這個修正是不夠的,因為SolarWinds.MessageBus.Models.Indication可以用來傳播一個攻擊者控制類型的內部對象。通過控制類型,我們就可以通過遠程執行惡意代碼來控制目標系統的漏洞!
CVE-2022-36958SolarWinds定義了一些稱為“SWIS動詞”的內部方法/操作。這些動詞可以是:
1.通過API直接調用。
2.通過Orion平台Web UI間接調用(Orion平台內部調用動詞)。
關於SWIS動詞,我們需要了解以下2點:
1.它們是使用XML結構中的有效負載調用的。
2.它們接受預定義類型的參數。
例如,Orion.AgentManagement.Agent.Deploy動詞接受12個參數。下面的屏幕截圖顯示了這些參數及其相應的類型。
Orion.AgentManagement.Agent.Deploy的參數
參數的處理是通過方法SolarWinds.InformationService.Verb. VerbExecutorContext.UnpackageParameters(XmlElement[], Stream)執行的。
在[1]處,檢索給定動詞參數的Type;在[2]處,使用檢索到的參數類型初始化DataContractSerializer;在[3]和[4]處,參數被反序列化。
這是正在處理一個DataContractSerializer。不過,這樣我們無法控制反序列化類型。
目前已找到了一些可濫用的PropertyBag類,通過進一步分析,有多個SWIS動詞接受名為SolarWinds.InformationService.Addons.PropertyBag類型的參數。我們可以提供任意XML,將其反序列化為這種類型的對象。
在[1]處,定義了ReadXml方法,它將在反序列化期間被調用;在[2]處,代碼遍歷所提供的項;在[3]處,檢索到關鍵元素。如果存在,則繼續執行代碼;在[4]處,檢索type元素的值。人們可以放心地猜測它接下來如何執行;在[5]處,檢索到value元素;在[6]處,調用Deserialize方法,輸入值和類型標記中包含的數據;在[7]處,序列化的有效負載和類型名稱被傳播給SolarWinds.InformationService.Serialization.SerializationHelper.Deserialize方法。
同樣,類型和序列化的有效負載都由攻擊者控制。讓我們檢查一下這個反序列化方法。在[1]處,代碼檢查所提供的類型是否被緩存。如果不是,則從[2]處的字符串中檢索類型。在[3]處,調用靜態的DeserializeFromStrippedXml。靜態的DeserializeFromStrippedXml方法通過調用SerializationHelper.serializerCache.GetSerializer(type)來檢索序列化器對象。然後,它在檢索到的序列化器對像上調用(非靜態)DeserializeFromStrippedXml(string)方法。
如何檢索序列化器在[1]處,代碼嘗試從緩存中檢索序列化器。在緩存缺失的情況下,它通過調用GetSerializerInternal([2])來檢索序列化器,因此我們繼續使用GetSerializerInternal進行調查。
在[3]處,根據攻擊者控制的類型檢索XmlTypeMapping。它沒有執行任何安全措施。它僅用於檢索關於給定類型的一些基本信息。
在[4]處,初始化XmlStrippedSerializer對象。為構造函數提供了四個參數:
1.一個新的XmlSerializer實例,其中序列化器的類型由攻擊者控制。
2.目標類型的XsdElementName,從XmlTypeMapping獲得。
3.該類型的Namespace,也是從XmlTypeMapping獲得的。
4.類型本身。
到目前為止,我們可以發現:
1.我們正在切換反序列化器。使用DataContractSerializer對整個SWIS動詞有效負載和參數進行反序列化。但是,PropertyBag對象最終將使用XmlSerializer進行反序列化。
2.我們完全控制提供給XmlSerializer構造函數的類型,這是利用它的關鍵條件。
似乎我們有它,通過反序列化中的類型控制的另一個RCE。由於XmlSerializer可能會通過ObjectDataProvider被濫用,我們可以將目標反序列化類型設置為以下類型:
但是,在成功利用漏洞之前,還有必要分析XmlStrippedSerializer.DeserializeFromStrippedXml(String) 。
可以發現,在[1]處,正在創建一個新的XML字符串。它的結構如下:
綜上所述:
1.攻擊者的XML被一個從傳播的類型派生的標記封裝,請參閱GetSerializerInternal方法。
2.檢索到的Namespace被插入到xmlns屬性中。攻擊者控制最終XML的主要片段並控制類型。然而,由於自定義的XML封裝,ysosserial.netgadget將無法開箱即用。
生成的gadget如下所示:
第一個標記等於ExpandedWrapperOfLosFormatterObjectDataProvider。此標記將由DeserializeFromStripedXml方法自動生成,因此我們需要將其從生成的有效負載中刪除!當我們這樣做時,下面的XML將被傳播給XmlSerializer.Deserialize方法。
當你比較原始的ysosserial.net gadget和我們當前的gadget時,可以發現一個很大的區別:
1.原始gadget在根標記中定義了兩個名稱空間:xsi和xsd。
2.當前gadget僅包含一個空xmlns屬性。
ObjectInstance標記依賴於xsi命名空間。因此,反序列化將失敗。
幸運的是,不必在根標籤(roottag)中專門定義命名空間,RootTag是用於標記React Native 原生根視圖層的不透明標識符(opaque identifier)。因此,我們可以通過在ProjectedProperty0標記中定義這兩個名稱空間來修復gadget。
通過這種方式,我們得到了第三個RCE,這樣,我們就完全控制了目標反序列化類型。
CVE-2022-36964技術層面,該漏洞與CVE-2022-36958相同,但是,它存在於共享ReadXml方法的相同實現的不同類中。在本例中,易受攻擊的類是SolarWinds.InformationService.Contract2.PropertyBag。
TestAlertingAction SWIS動詞接受此類型的參數,因此該漏洞可通過API加以利用。
總結我們在本文介紹了SolarWinds中的四個不同的反序列化漏洞,攻擊者可以使用這些漏洞控制反序列化對象的類型,以及介紹瞭如何通過使用自定義反序列化gadget繞過它們。目前,SolarWinds也對這些繞過進行了修復。
Recommended Comments