隱祕的角落 -- JDK CORBA 安全性研究(下)

作者:螞蟻安全非攻實驗室
公衆號:螞蟻安全實驗室

背景

上一篇中我們初步分享了 CORBA 通信過程以及各種名詞去了解這個協議,並且搭建了一個 demo,接下來會使用這個 demo 進行分析 CORBA 中的一些風險點。

Client

一、思路分析

安全分析方向有兩個:

  1. 在解析 server 返回的 response 時,可能存在 jdk 原生反序列化

  2. 在 client 端生成 stub 類時,很有可能存在類加載邏輯,甚至是加載遠程類

二、反序列化分析

發生在 stub 的使用階段,在 client 發起 dii request 後,惡意服務器可以精心構造返回數據,進而控制 client 端對 response 的反序列化操作流程,其中存在 JDK 原生反序列化,由此觸發 java 反序列化 rce。

1、原理分析

漏洞觸發代碼如下:

Request request = hello._request("sayHello");

request.invoke();

System.out.println(request.result().value());

request.invoke(); 調用處理流程如下:

由上圖可見,在使用 dii request 發起 rpc 請求時,能夠觸發 ObjectInputStream#readObject ,引發 JDK 原生反序列化。

其中 IDLJavaSerializationInputStream 不是 CORBA 通信過程中默認的反序列化工具,默認的是 CDRInputStream_x_x (x_x 根據版本決定),那麼我們接下來深入分析下如何創建 IDLJavaSerializationInputStream 對象作爲反序列工具的,流程如下:

整個 IDLJavaSerializationInputStream 對象生成流程如上所述,最關鍵的地方只有一處調用:MessageBase#readGIOPHeader

這一處調用主要功能是處理 server 端的返回信息,是根據 server 端的返回數據生成 message header,依次控制後續對數據的拆包、解析操作。其流程中,requestEncodingVersion 變量就是控制通信實現方式,默認是 CDR 的形式,最後會生成 CDRInputStream_x_x 來進行解析操作(例如,調用 impl.read_wstring() 的時候,就會調用 CDRInputStream_X_X)。

此處的流程能觀察到,requestEncodingVersion 是可以由 server 端返回流進行控制的,即 server 端可以控制 client 端的拆包解析方式。

經過深入分析,就算 server 端可以控制一部分 client 端的行爲,要想觸發到 JDK 反序列化代碼,還必須要求 client 端含有如下配置,以此開啓 JDK 序列化功能支持:

props.put("com.sun.CORBA.encoding.ORBEnableJavaSerialization", "true");

ORB orb = ORB.init(args, props);

2、風險前置條件

兩個前置條件:

  1. client 端需要開啓 JDK 序列化功能支持

  2. client 端需要發起 dii 請求,並且需要預先指定:調用返回結果類型 or 調用參數類型

第一個條件,需要在初始化 ORB 時,需要開啓 iiop 協議的 jdk 序列化技術支持。

注:實際上就是從 CDR 支持轉爲 jdk 序列化支持,默認情況下是 CDR 支持 。

第二個條件,需要 client 端在 dii 請求發起前,手動設置調用返回結果類型或是調用參數類型,纔會在 response 處理時,觸發到 JDK 反序列化。

原因在於如下圖(com.sun.corba.se.impl.corba.RequestImpl#unmarshalReply):

如上圖,該流程是在 server 端返回 response 後的 client 端對數據進行解包的流程,默認情況下 _result 、 _arguments 都是爲 null 的。需要在初始化創建時候,傳入相關配置才能在解析返回結果時觸發 read_value 調用,最終能夠觸發 JDK 反序列化。

附上存在反序列化風險的 client 端代碼:

public void run(String[] args) throws Exception {

        Properties props = new Properties();

        // 生成一個ORB,並初始化,這個和Server端一樣

        props .put("org.omg.CORBA.ORBInitialPort", "1050");

        props.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1");

        // allowed java serial

        props.put("com.sun.CORBA.encoding.ORBEnableJavaSerialization", "true");

        final ORB orb = ORB.init(args, props);

        // 獲得根命名上下文

        org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");

        // 用NamingContextExt代替NamingContext.

        NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

        // 通過名稱獲取服務器端的對象引用

        String name = "Hello";

        Hello hello = HelloHelper.narrow(ncRef.resolve_str(name));

        //調用遠程對象

        Request req = hello._create_request(null, "sayHello", null, new NamedValue() {

            @Override

            public String name() {

                return null;

            }

            @Override

            public Any value() {

                Any any = new AnyImpl((com.sun.corba.se.spi.orb.ORB) orb);

                any.insert_wstring("1");

                return any;

            }

            @Override

            public int flags() {

                return 0;

            }

        });

        req.invoke();

    }

三、遠程類加載分析

發生在 stub 的生成階段,惡意服務器可以指定 codebase ,client 端會從 codebase 指定地址進行遠程類加載。

1、原理分析

我們可以去查看下 _HelloStub#readObject 函數,源碼如下:

  private void readObject (java.io.ObjectInputStream s) throws java.io.IOException

  {

     String str = s.readUTF ();

     String[] args = null;

     java.util.Properties props = null;

     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);

   try {

     org.omg.CORBA.Object obj = orb.string_to_object (str);

     org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate ();

     _set_delegate (delegate);

   } finally {

     orb.destroy() ;

   }

  }

如上,根據規定 readObject 函數會還原一個 _HelloStub 對象 ,那麼上述代碼塊中:

org.omg.CORBA.Object obj = orb.string_to_object (str);

這一句代碼就是將協議串轉換爲 client stub 的操作,協議串可以是 IOR: /corbaname:/ corbaloc: 開頭

經過分析, orb.string_to_object (str); 調用整個處理過程如下:

如上圖,最主要的是 _NamingContextExtStub#resolve_str 這一步調用,大致功能是由 NamingContext 從 orbd 中獲取 stub 類,其中涉及到了類加載的過程。

從 _NamingContextExtStub#resolve_str 往後的調用過程,和正常的 client 端從 NamingServer 獲取對象引用的操作是一樣的,如下:

// 通過名稱獲取服務器端的對象引用

String name = "Hello";

Hello hello = HelloHelper.narrow(ncRef.resolve_str(name));  // 調用 resolve_str

由此可見,無論是 stub 類的 readObject 函數,還是正常的 client rpc 調用,都可能會觸發到遠程類加載流程。

2、風險前置條件

需要 client 端允許 RMI 上下文環境訪問遠程 codebase。

StubFactoryFactoryStaticImpl#createStubFactory 中的類加載使用的是 RMIClassLoader ,雖然 useCodebaseOnly 爲 false ,但是在反序列化 stub 上下文中,沒有允許訪問 codebase,會導致 SecurityManager 權限校驗不通過

3、分析小結

· Message:

每一次 request 和 reponse 的運載物都是它。在 corba 通信過程中,CorbaMessageMediatorImpl 就是它們的代表,其中包含 requestHeader, replyHeader, messageHeader,這三者分別管控 request 包的序列化/反序列化,replay(response)包的序列化/反序列化,message的序列化/反序列化,主要作用是控制通信數據格式。

· request & response:

request 和 response 都可能是 CDRInputObject 或者 CDROutputObject,站在分析者的角度,主要關注 CDRInputObject。在根據 requestHeader, replyHeader, messageHeader 反序列化時,都是使用 CDRInputObject 作爲操作對象對數據進行處理的

數據底層處理類:

  1. CDROutputObject

  2. CDRInputObject

實際在序列化/反序列化數據時,是由它們的 impl 屬性實現的,可以分爲 IDLJavaSerializationX 和 CDRX 系列,如下圖關係:

Corba Server 端

一、思路分析

server 端是先綁定 rpc 實現( 註冊 servant ),然後會和 client 端進行交互。

經過分析沒有發現遠程類加載的情況,但是存在和 client 端的反序列化風險類似的問題,因爲本質上都會有底層數據經過 CorbaMessageMediator 的處理過程,不過觸發 JDK 反序列化的入口點不一樣。

二、反序列化分析

該風險發生在 client 端發起 rpc 請求時產生,在 server 端調用實際 rpc 服務函數實現前觸發。

1、原理分析

過程在分派請求時發生,我們重寫 hello.idl 如下:

module com {

    interface Hello{

        string sayHello (in wstring name);

    };

};

如上代碼,定義 sayHello 入參類型爲 wstring ,接着查看 HelloPOA#_invoke ,源碼如下

 public org.omg.CORBA.portable.OutputStream _invoke (String $method,

                                org.omg.CORBA.portable.InputStream in,

                                org.omg.CORBA.portable.ResponseHandler $rh)

  {

    org.omg.CORBA.portable.OutputStream out = null;

    java.lang.Integer __method = (java.lang.Integer)_methods.get ($method);

    if (__method == null)

      throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);



    switch (__method.intValue ())

    {

       case 0:  // com/Hello/sayHello

       {

         String name = in.read_wstring ();

         String $result = null;

         $result = this.sayHello (name);

         out = $rh.createReply();

         out.write_string ($result);

         break;

       }



       default:

         throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);

    }



    return out;

  } // _invoke

如上,在調用真正的 sayHello 函數服務之前,_invoke 函數先還原了入參 name ,調用的是 CDRInputStream#read_wstring ,後續的處理流程於 Client 反序列化分析中流程相同。

2、風險前置條件

server 端要存在入參,且參數類型可以觸發到 JDK 反序列化流程,例如 any 、wstring 等

3、注意

以上所述都是通過 Oracle JDK 搭建的最簡單 Corba 通信環境分析出來的,在其他大型中間件/容器等對 Corba 的擴展實現中可能會存在更多的 JDK 反序列化風險點,其調用鏈路可能也有所不同,但是漏洞原理大多是一致的。

例如 read_any 函數調用也會觸發到反序列化,這是今年 weblogic 和 websphere 被刷的 IIOP 反序列化漏洞入口。

ORBD

全稱:The Object Request Broker Daemon

orbd 是用於產生 NameService 的服務,在 server 端進行 corba 服務實現註冊的之前,首先需要運行 orbd。

簡介見:https://docs.oracle.com/javase/1.5.0/docs/guide/idl/orbd.html

一、前置知識

orbd 其實在 jdk 中有所實現,見 com.sun.corba.se.impl.activation.ORBD 。

注:需要調試的話,在 idea Configuration 中配置好 Program arguments :

-port 1050 -ORBInitialPort 1049 -ORBInitialHost 127.0.0.1

orbd 主要是爲 server 端提供長期存儲服務/存儲上下文/計數等功能。client 端也是首先通過它取得 server 端的信息,在最後的 rpc 調用時,纔會直接和 server 端通信,在查找 name service / 查找 corba servce 時,都是與 orbd 通信的。

orbd 中進行數據的採集和整理也是使用的 CorbaMessageMediatorImpl#handleInput,通過 CorbaServerReqeustDispatcherImpl#dispath 進行請求分派。

在直接使用 orbd 時,會在工作目錄下創建 orb.db 目錄,該目錄下存儲了 server / 上下文(NamingContextImpl) 等信息,目的是爲了保持 corba 服務相關對象的持續保存,如下圖:

二、反序列化分析

在 corba client 角色發起調用請求時會出現反序列化的操作,會將 orb.db 文件夾下的 NC0 文件內容進行反序列化,路徑是 client 角色端可控的。

注:server 端 / client 端都會充當 corba client 角色,只要是調用了 org.omg.CORBA.portable.ObjectImpl#_request 接口都可視作 client 角色。

1、原理分析

orbd 可以將 NamingContextImpl / server 等信息持續化保存(序列化過程),那麼一定會有機會將它們從本地磁盤導入到程序中(反序列化過程)。

這裏我們直接查看反序列化過程,如下

通過前文對 Server 的派遣請求流程的分析,我們能夠觀察到 ORBD 在接收到請求後分派的處理方式大致相同,不過這裏多一個預處理流程,在預處理流程中就存在 JDK 反序列化的操作。

其中 ServantManagerImpl#readInContext 代碼如下

public NamingContextImpl readInContext(String objKey)

{

    NamingContextImpl context = (NamingContextImpl) contexts.get(objKey);

    if( context != null )

    {

        // Returning Context from Cache

        return context;

    }



    File contextFile = new File(logDir, objKey);

    if (contextFile.exists()) {

        try {

            FileInputStream fis = new FileInputStream(contextFile);

            ObjectInputStream ois = new ObjectInputStream(fis);

            context = (NamingContextImpl) ois.readObject();

            context.setORB( orb );

            context.setServantManagerImpl( this );

            context.setRootNameService( theNameService );

            ois.close();

        } catch (Exception ex) {

        }

    }



    if (context != null)

    {

        contexts.put(objKey, context);

    }

    return context;

}

如上代碼,該處理過程是將 objKey 當作 logDir 目錄的子文件,然後提取文件內容,直接調用 readObject 函數,觸發 jdk 原生反序列化。

那麼 objKey 是從哪兒獲取的呢?

在 client 角色方得到 _NamingContextExtStub 對象後,就可以直接調用 Name service 提供的服務,例如 rebind、unbind、bind 等等,其中 _NamingContextExtStub 含有 orbd 的相關信息,將其中 IOR 提取出來後,可以看見一些 corba server 制定的數據處理規則等,其中有一個 ObjectId 的對象,它裏面的 id 屬性就是 objKey 的 byte[] 格式,如下圖:

這裏產生的安全風險是,orbd 居然將 client 角色傳遞過來的 ObjectId 進行還原,然後在處理過程中轉換爲 ojbKey ,簡而言之,client 角色可以自行修改 ObjectId 中的任何信息,並且 orbd 不僅會還原它,還會將其製作爲 ojbKey ,接着進行 NamingContextImpl 的預加載。

惡意 Client 可以通過控制 ObjectId 間接控制 ORBD 中的 NC0 文件路徑,在 ORBD 服務器中如果存在含有惡意序列化數據的文件,那麼就可以通過 ObjectId 可以將反序列化文件的路徑指向惡意文件,最終會導致 ORBD 服務器觸發 JDK 反序列化漏洞。

2、風險前置條件

需要 ORBD 服務器中存在惡意 Java 序列化數據的文件。

不過,orbd 在標準的 corba 通信中,是直接使用命令行運行的,並不會帶上其他依賴,也不需要。即使存在惡意文件,但是最終無法使用目前已知的反序列化 gadget 進行攻擊,至少都得需要 jdk 原生反序列化的 gadget 纔會導致任意代碼執行。

三、分析小結

client & server:

絕對的 server 端是 orbd,它永遠只提供數據轉發、name service 服務這些功能,絕對的 client 是 corba client ,它對 orbd 、corba server 發請求,而 corba server 是一會兒 client 角色,一會兒 server 角色。在 corba 通信過程中,client 角色總會發起 invoke 請求(發包 request),然後收到 reply(接包 response),server 端自然總是收到 request ,然後返回 response。

ORBD 這一角色漸漸被 Corba Server 所整合,在某些容器中是不用特意去配置 ORBD 的,直接使用 JNDI 的方式註冊、發佈 service 即可。但是 ORBD 含有的功能不會被抹去,在其他 Corba 實現/擴展中肯定還是會存在功能模塊,負責處理 ORBD 原本的工作。

RMI-IIOP

一、簡介

曾經 JAVA 中分佈式解決方案只有 RMI 和 CORBA,兩者並不能共存,而 CORBA 又有跨語言的有點,所以推出了 RMI-IIOP 解決方案,此後 RMI 服務器對象可以使用 IIOP 協議,並與任何語言編寫的 CORBA 客戶端對象進行通信。(請參閱在 IIOP 上運行 RMI 程序時的一些限制,掃描下方二維碼查看)

RMI-IIOP 結合了 RMI 的易用性與 CORBA 的跨語言互操作性,將 Java 語言進一步推向了目前服務器端企業開發的主流語言的領先地位。

二、前置知識

IIOP (Internet Inter-ORB Protocol):IIOP 是 CORBA 的通信協議,用於 CORBA 對象RPC請求之間的交流。

IDL :IDL 全稱接口定義語言,是用來描述軟件組件接口的一種規範語言。用戶可以定義模塊、接口、屬性、方法、輸入輸出參數。Java 中提供了 idlj 命令用來編譯 IDL 描述文件,用以生成 Java 語言的 客戶端 java 文件等。

1、corba & RMI 差異

corba RMI
定義接口 idl 代碼生成接口 interface 定義
實現類 繼承 idlj 生成的 _NameImplBase 繼承 UnicastRemoteObject
使用語言 獨立於語言的,兼容性強 Java to Java
查找對象 使用 CosNaming(nameserver) 使用 JNDI 定位遠程對象
序列化/反序列化 默認採用 CDR 序列化數據 使用 JDK 原生反序列化

rmi 和 corba 都差不多,都是樁和框架的設計。它們在 java 中都可以相互調用,這就歸功於 rmi-iiop。

2、實現簡述

籠統地來說,rmi-iiop 是把 corba 整個實現給包裝了一次,在 corba 實現中,只能傳遞簡單的數據,沒法像 rmi 這樣能夠直接利用序列化/反序列化傳遞對象(這裏可能有誤,但暫時不知道如何通過 corba 直接傳遞對象),在 r mi-iiop 實現中,把 corba 的通信模式 GIOP-TCP 包裝了一層,間接的實現了對象的傳遞,如下圖:

比起 corba 的底層數據處理,多出來了 IIOP 這麼一層,它的工作是將對象拆分,對象數據就是由對象中的屬性構成,直接傳輸對象的屬性,就能夠間接的傳遞對象了。

3、調用流程差異

github 上一個 rmi-iiop 例子:https://github.com/uro/cobra-rmi-iiop

client 端:

這麼三句代碼,就能拿到 stub,都是 jndi 的功勞。其中 lookup 函數可以傳入 corbaloc 、corbaname 等協議串,例如:ctx.lookup("corbaname::localhost:1050#PhoneDirectoryService")。

server 端:

同樣也是三句代碼就能綁定 corba 服務實現,這也是 jndi 的功勞。

注:以上都需要使用 作者給出的 jndi.properties ,也可以直接指定 jvm 參數(因爲要用到 ORBD)。

demo 補充

如果想測試一下 rmi-iiop 關於 對象 傳遞的demo,可以在上述例子中加入如下類:

package zad1;



public class SerClass implements java.io.Serializable {

    // members

    private int x;

    private String myString;

    // constructor

    public SerClass(int x, String myString) throws java.rmi.RemoteException {

        this.x=x;

        this.myString=myString;

    }



    // some accessor methods

    public int getX() {  return x;}

    public void setX(int x) { this.x=x; }

    public String getString() {  return myString;  }

    public void setString(String str) { myString=str; }

}

PhoneBookClient 中獲取 stub 後,添加一個調用:

SerClass sc = new SerClass(5, "Client string! ");

// pass the class to be altered on the server

// of course behind the scenes this class is being

// serialized over IIOP

sc = pd.alterClass(sc);

// now let's see the result

System.out.println("Serialization results :\n"+

                   "Integer was 5 now is "+sc.getX()+"\n"+

                   "String was \"Client String! \"" +

                   "now is \""+sc.getString()+"\"");

PhoneDirectoryInterface 增加接口函數

package zad1;



import java.rmi.Remote;

import java.rmi.RemoteException;



public interface PhoneDirectoryInterface extends Remote {



    String getPhoneNumber(String name) throws RemoteException;



    boolean addPhoneNumber(String name, String num) throws RemoteException;



    boolean replacePhoneNumber(String name, String num) throws RemoteException;



    public SerClass alterClass(SerClass classObject) throws java.rmi.RemoteException;

}

PhoneDirectory 增加函數實現:

@Override

public SerClass alterClass(SerClass classObject) throws RemoteException {

    // change the values of SerClass and return it.

    // add 5 to X

    classObject.setX( classObject.getX() + 5 );

    // alter the string

    classObject.setString( classObject.getString() + " : I've altered you" );

    return classObject;

}

三、反序列化分析

其實從設計上來看,安全分析思路已經很明顯了,利用 IIOP 的序列化/反序列化能力,構造惡意 jdk serial 數據讓目標對其反序列化。

這裏的承載對象就要好好考量一下了(因爲 IIOP 在反序列化數據處理時,都是根據調用者(servant) 或者 stub 指定的預期類型(expectType)來確定反序列化的處理流程),風險最大的情況的就是使用 java.lang.Object 作爲遠程調用函數參數、遠程調用函數返回值。

IIOP 有關目標對象創建、反序列化處理等都發生在 IIOPInputStream 這個類中,反序列化入口在 com.sun.corba.se.impl.io.IIOPInputStream#simpleReadObject 。

其處理流程如下:

  1. 先根據 expectType 新建一個對象,並判斷該類是否含有 readObject 函數(實現了 Serialization 接口),如果有,則調用該函數

  2. 如果沒有該函數,那麼通過反射,取出該對象的所有 field ,然後從 IIOPInputStream 讀取值,塞入各個 field 中。其中,如果 field 不是基本類型,那麼根據其類型創建對象,重複步驟1

上述過程發生在如下情況中:

  1. client 端發起請求後,反序列化 server 端的返回結果

  2. server 端在接受到 client 端到請求後,反序列化請求參數

風險種類和場景根據角色的不同而不同。

注意,IIOPInputStream 主要是將 CDRInputObject 包裝,然後在讀取各種數據時,實際上還是利用的 CDRInputStream_X_X 或 IDLJavaSerializationInputStream

但是 IIOPInputStream 本身也存在風險點,那就是會首先判斷反序列化目標是否存在 readObject 函數,然後對其進行調用,由此會觸發 JDK 反序列化風險。

RMI-IIOP 具體存在的安全風險,形如最原始的 rmi 攻擊 rmiserver 那般,server 端存在入參類型爲 java.lang.Object 或其屬性中含有 java.lang.Object 類型等情況 ,此時惡意 client 端可以在 rpc 調用的時候,傳入惡意類,然後使用 java.lang.Object 來承載該類的服務端進行反序列化。

rmi 攻擊分析見:https://xz.aliyun.com/t/6660#toc-6

安全建議

建議在實際業務場景中儘量減少涉及到序列化功能的接口/服務的公開,如非必須可以選擇將其關閉,例如 weblogic 可選擇關閉 IIOP / T3 協議支持。

現階段,JAVA ODD類型反序列化安全沒有永絕後患的解決方案。如果你的設計落入了ODD模式,那麼註定是一個安全夢魘,正如近幾年整個安全業界面臨fastjson不停爆出0day時張皇失措的情景。現在fastjson也提供了安全模式,關閉開放動態類型反序列化模式,這個是解決此類安全隱患的正途。

在因爲種種原因無法規避ODD時,可以選擇通過 JEP290 防護機制設置全局黑白名單,但是需要將 JDK 版本升級到 JDK9 或是 8u121、7u131 和 6u141。在實際場景中推薦結合業務而配置白名單,如果實在不行可以退而求其次配置惡意類黑名單。但是注意黑名單容易被繞過,這個也是fastjson社區之前常年雞飛狗跳的原因。

另外,由於這兩年業界在RASP/安全切面領域的實踐,對於ODD漏洞類型的緊急止血可以從傳統WAF的痛苦中解脫出來。比如可以用RASP/安全切面機制禁止危險反序列化函數調用高危操作,在面對未知0day漏洞時能夠有效緩解漏洞造成的影響。

注:JEP290 默認只會開啓 RMI 安全防護,如果要配置全局反序列化黑白名單,需要在配置文件 conf/security/java.properties 中的 jdk.serialFilter 條目設置反序列化黑白名單列表,配置參考(掃描下方二維碼查看)

作者感想

本着以安全技術分析、思路分享的態度發文,文章沒有經過太多雕琢,如有錯誤歡迎大佬們指正。

2019年9月分析完了 JDK CORBA ,但是沒有及時向上分析JAVA框架/應用層面錯失了很多 0day。

總的來說,本系列文章都是圍繞反序列化/類加載/類初始化等角度去進行安全分析,沒有從 CORBA 協議本身的一些設計角度去分析,CORBA 中很重要的功能就是分佈式對象管理和調遣,並且 JAVA 語言也是面向對象的典範,所以本系列文章更多的關注在“對象”這個點上,如果讀者感興趣可以從協議設計安全角度深入分析。

參考文獻

什麼是 RMI、IIOP和RMI-IIOP:https://www.ibm.com/support/knowledgecenter/zh/SSYKE2_7.0.0/com.ibm.java.lnx.70.doc/rmi-iiop/overview.html

jndi 對 corba 的支持:https://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-cos.html

java 中 rmi 和 corba 的區別:https://blog.csdn.net/njchenyi/article/details/468402

RMI、CORBA、IIOP簡單實例:https://blog.csdn.net/javamxj/article/details/282664

關於作者

螞蟻安全非攻實驗室:隸屬於螞蟻安全九大實驗室之一。螞蟻安全非攻實驗室致力於JAVA安全技術研究,覆蓋螞蟻自研框架和中間件、經濟體開源產品以及行業中廣泛使用的第三方開源產品,通過結合程序自動化分析技術和AI技術,深度挖掘相關應用的安全風險,構建可信的安全架構解決方案。


Paper 本文由 Seebug Paper 發佈,如需轉載請註明來源。本文地址:https://paper.seebug.org/1446/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章