Java安全之Weblogic 2016-3510 分析
阿新 • • 發佈:2021-01-13
# Java安全之Weblogic 2016-3510 分析
首發安全客:[Java安全之Weblogic 2016-3510 分析](https://www.anquanke.com/post/id/226656#h2-0)
## 0x00 前言
續前面兩篇文章的T3漏洞分析文章,繼續來分析CVE-2016-3510漏洞,該漏洞一樣是基於,前面的補丁進行一個繞過。
[Java安全之初探weblogic T3協議漏洞](https://www.cnblogs.com/nice0e3/p/14141925.html)
[Java安全之Weblogic 2016-0638分析](https://www.cnblogs.com/nice0e3/p/14207435.html)
## 0x01 工具分析
這裡還需要拿出上次的weblogic_cmd的工具來看一下CVE-2016-3510的命令執行payload怎麼去進行構造。
來到原始碼中的Main這個入口點這裡,前面的TYPE需要修改為`marshall`,因為這次是需要使用到`MarshalledObject`來進行封裝物件。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213851264-1655589556.png)
填入引數,打個斷點測試一下。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213900387-859610183.png)
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213908420-115163350.png)
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213919162-1507504588.png)
前面的都分析過了,在此略過,主要是這張圖片裡面的地方傳入命令,並且生成payload,跟蹤進行檢視。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213929572-429875001.png)
這裡的`blindExecutePayloadTransformerChain`方法是返回構造利用鏈的`Transformer[]`陣列內容,這裡主要來跟蹤`serialData`方法。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213937521-1370136963.png)
該方法中是將剛剛構造好的`Transformer[]`陣列傳入進來,聯合下面的程式碼構造成了一個惡意的物件,然後呼叫`BypassPayloadSelector.selectBypass`方法處理這個惡意的物件。跟蹤檢視該方法的實現。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213947558-1025979898.png)
這個位置呼叫了`marshalledObject`方法處理payload,跟蹤檢視。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112213956147-2003965625.png)
`marshalledObject`內部使用了`MarshalledObject`的構造方法,將payload作為引數傳遞進去。然後得到該值。這裡payload就構造好了。
跟蹤進`MarshalledObject`裡面進行檢視。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214004002-496714042.png)
這個地方又new了一個`MarshalledObject.MarshalledObjectOutputStream`物件,跟蹤檢視。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214013343-1476566331.png)
`MarshalledObject.MarshalledObjectOutputStream`繼承了`ObjectOutputStream`物件,並且呼叫的是父類的構造器。這就和直接new一個`ObjectOutputStream`沒啥區別。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214022064-1689799071.png)
var1是我們傳遞進來的payload,在這裡使用的是CC1的利用鏈,var1也就是一個惡意的`AnnotationInvocationHandler`物件。var2是`ByteArrayOutputStream`物件,var3相當於是一個`ObjectOutputStream`物件。在這裡會將var1 的內容進行序列化後寫入到var2裡面。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214029414-1210840326.png)
而序列化後的物件資料會被賦值給`MarshalledObject`的`this.objBytes`裡面。
執行完成,退回到這一步過後,則是對構造好的`MarshalledObject`物件呼叫`Serializables.serialize`方法進行序列化操作。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214037405-759918697.png)
## 0x02 漏洞分析
在前面並沒有找到CVE-2016-0638漏洞的補丁包,那麼在這裡也可以直接來看到他的利用方式。
前面CVE-2016-0638這個漏洞是基於前面的補丁將payload序列化過後封裝在`weblogic.jms.common.StreamMessageImpl`類裡面,然後進行反序列化操作,`StreamMessageImpl`類會呼叫反序列化後的物件的readobject方法達成命令執行的操作。而補丁包應該也是在ClassFileter類裡面將上次我們利用的`weblogic.jms.common.StreamMessageImpl`類給進行拉入黑名單中。
那麼在該漏洞的挖掘中又找到了一個新的類來對payload進行封裝,然後繞過黑名單的檢測。
而這次使用得是`weblogic.corba.utils.MarshalledObject`類來進行封裝payload,將payload序列化過後,封裝到`weblogic.corba.utils.MarshalledObject`裡面,然後再對`MarshalledObject`進行序列化`MarshalledObject`,`MarshalledObject`不在WebLogic黑名列表裡面,可以正常反序列化,在反序列化時`MarshalledObject`物件呼叫`readObject`時,對`MarshalledObject`封裝的序列化物件再次反序列化,這時候繞過黑名單的限制,對payload進行反序列化操作觸發命令執行。
下面來直接看到`weblogic.corba.utils.MarshalledObject#readResolve`方法的位置
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214050738-1806617204.png)
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214059259-729669130.png)
這地方就有意思了,前面在分析工具的時,我們得知構造的繞過方式是將payload序列化放在這個`this.objBytes`中,而在此如果呼叫`MarshalledObject.readResolve`方法就可以對被封裝的payload進行反序列化操作。達到執行命令的效果。
在這裡還需要思考到一個問題`readResolve`這個方法會在什麼時候被呼叫呢?
在Weblogic從流量中的序列化類位元組段通過readClassDesc-readNonProxyDesc-resolveClass獲取到普通類序列化資料的類物件後,程式依次嘗試呼叫類物件中的readObject、readResolve、readExternal等方法。而上一個CVE-2016-0638的漏洞就是藉助的`readExternal`會被程式所呼叫的特點來進行繞過。我們這次使用的是`readResolve`這個方法,這個方法也是同理。
後面也還需要知道一個點,就是反序列化操作過後,`readResolve`具體是如何觸發的?下來來斷點檢視就清楚了。
先在`InboundMsgAbbrev.ServerChannelInputStream#resolveClass`方法先打一個斷點,payload傳送完成後,在該位置停下。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214120837-171159315.png)
在這這裡可以看到傳遞過來的是一個`MarshalledObject`物件,不在黑名單中。
那麼下面在`readResolve`上下個斷點看一下呼叫棧。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214121834-94097499.png)
在這裡面會被反射進行呼叫,再前面的一些方法由於不是原始碼進行調式的跟蹤不了。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214138253-439023904.png)
回到`weblogic.corba.utils.MarshalledObject#readResolve`方法中檢視
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214150151-855190178.png)
和前面說的一樣,這裡new了一個`ByteArrayInputStream`物件,對`this.objBytes`進行讀取,前面說過我們的payload封裝在`this.objBytes`變數裡面,而這時候new了一個`ObjectInputStream`並且呼叫了`readObject`方法進行反序列化操作。那麼這時候我們的payload就會被進行反序列化操作,觸發CC鏈的命令執行。
先來檢視docker容器裡面的內容
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214201987-1085918364.png)
然後執行來到下一行程式碼中。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214210914-1317492019.png)
readobject執行過後,再來檢視一下docker裡面的檔案有沒有被建立。
![](https://img2020.cnblogs.com/blog/1993669/202101/1993669-20210112214218595-380003289.png)
檔案建立成功,說明命令能夠執行。
## 0x03 結尾
本文內容略少,原因是因為很多內容都是前面重複的,並不需要拿出來重新再敘述一遍。這樣的話並沒有太大的意義,如果沒有分析過前面的兩個漏洞,建議先從前面的CVE-2015-4852和CVE-2016-0638這兩個漏洞除錯分析起,除錯分析完前面的後面的這些繞過方式理解起來會比較