溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞

發(fā)布時(shí)間:2021-11-30 14:47:07 來源:億速云 閱讀:181 作者:iii 欄目:安全技術(shù)

本篇內(nèi)容主要講解“怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞”吧!

CORBA,即公共對象請求代理體系結(jié)構(gòu),它是一個(gè)由對象管理組織(OMG)定義的標(biāo)準(zhǔn)化規(guī)范。它是一個(gè)獨(dú)立與平臺的RPC框架,并且早于SOAP和gRPC等標(biāo)準(zhǔn)出現(xiàn)。在分布式環(huán)境中,CORBA使用了互聯(lián)網(wǎng)InterORB協(xié)議(IIOP)來實(shí)現(xiàn)端點(diǎn)之間的通信。在IBM WebSphere的默認(rèn)安裝配置下,CORBA服務(wù)可以運(yùn)行在TCP端口2809、9100、9402和9403。在調(diào)用服務(wù)方法之前,Interceptor類將會攔截調(diào)用請求,這里我們需要注意的是TxServerInterceptor類。

CVE-2020-4450-snippet-1.java:

public void receive_request(ServerRequestInfo sri) {

  // ...snip...

    if (TxProperties.SINGLE_PROCESS) {

      propagationContext = TxInterceptorHelper.demarshalContext(serviceContext.context_data, (ORB)((LocalObject)sri)._orb()); // <------------

      contextType = TxInterceptorHelper.determineContextType(propagationContext);

    }  

  // ...snip...

}

 

public static final PropagationContext demarshalContext(byte[] bytes, ORB orb) {

  // ...snip...

  propContext.implementation_specific_data = inputStream.read_any(); // <-------

  // ...snip...

}

 

public Any read_any() {

  // ...snip...

  any.read_value(this.encoderStream, typeCodeImpl); // <------------------------

  return any;

}

 

private Object simpleReadObjectInternal(Class paramClass, String paramString) throws ClassNotFoundException, IOException {

  // ...snip...

      return readSerializable(paramClass, objectStreamClass, paramString); // <------

  // ...snip...

}

 

private Object readSerializable(Class paramClass, ObjectStreamClass paramObjectStreamClass, String paramString) throws IOException, ClassNotFoundException {

  // ...snip...

  return inputObjectClassDesc(serializable, paramObjectStreamClass); // <-------

}

 

private Object inputObjectClassDesc(Object paramObject, ObjectStreamClass paramObjectStreamClass) throws IOException, ClassNotFoundException {

  ObjectStreamClass objectStreamClass = processClassHierarchy(paramObject, paramObjectStreamClass);

  return inputObjectUsingClassDesc(paramObject, objectStreamClass); // <--------

}

 

  Object inputObjectUsingClassDesc(Object paramObject, ObjectStreamClass paramObjectStreamClass) throws IOException, ClassNotFoundException {

    // ...snip...

      ObjectStreamClass objectStreamClass = this.readObjectOSC;

      this.readObjectOSC = paramObjectStreamClass;

      paramObjectStreamClass.readObjectMethod.invoke(paramObject, this.readObjectArglist); // <--- calls readObject()

      this.readObjectOSC = objectStreamClass;

      return true;

}

當(dāng)TxServerInterceptor類成功攔截調(diào)用請求時(shí),便會調(diào)用receive_request()方法,同時(shí)還會試用demarshalContext()方法來從字節(jié)流中接收一個(gè)ServiceContext對象,而這個(gè)對象是攻擊者可控的。任何嵌入在這個(gè)字節(jié)流中的對象都可以通過調(diào)用read_any()方法來提取,最終通過調(diào)用readObject()方法來獲取嵌入的對象類。

遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2020-4450)

盡管我們可以實(shí)現(xiàn)對任何對象進(jìn)行反序列化操作,但實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行并非易事。這是因?yàn)镮BM Java SDK實(shí)現(xiàn)了針對反序列化攻擊的安全緩解措施,其中包括:

  • 擁有更嚴(yán)格的ClassLoader類,在運(yùn)行時(shí)僅提供必要的類;

  • TemplatesImpl類已無法再被序列化;

  • IBM SDK不會使用Oracle JDK的Java名命方法以及目錄接口(JNDI)。因此,我們無法通過RMI/LDAP來加載遠(yuǎn)程類并實(shí)現(xiàn)漏洞利用;

根據(jù)tint0的描述,tint0提供了一個(gè)Gadget鏈來繞過這種緩解方案。這個(gè)Gadget使用了WSIFPort_EJB類作為入口點(diǎn)。

CVE-2020-4450-snippet-2.java:

public class WSIFPort_EJB

  extends WSIFDefaultPort

  implements Serializable

 

{

  // ...snip...

 

  private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {

    ois.defaultReadObject();

    if (this.separatedEJBRefs) {

      Object objHome = ois.readObject();

      if (objHome != null && objHome instanceof HomeHandle) {

        HomeHandle homeHandle = (HomeHandle)objHome;

        this.fieldEjbHome = homeHandle.getEJBHome();

      }  

 

      Object obj = ois.readObject();

      if (obj != null && obj instanceof Handle) {

        Handle handle = (Handle)obj;

        this.fieldEjbObject = handle.getEJBObject();  // <----------------------

      }  

    }

  }

}

 

public EJBObject getEJBObject() throws RemoteException {

  // ...snip...

  home = (EJBHome)PortableRemoteObject.narrow(ctx.lookup(this.homeJNDIName), homeClass); // <----

  // ...snip...

  Method fbpk = findFindByPrimaryKey(homeClass); // <---- returns findFindByPrimaryKey() method

  this.object = (EJBObject)fbpk.invoke(home, new Object[] { this.key });   <--  $proxy.findFindByPrimaryKey(Serializable $arg)

}

這個(gè)類最有趣的地方在于getEJBObject()方法,我們一起來看一看這里面的JNDI查詢調(diào)用。

CVE-2020-4450-snippet-3.java:

com.sun.jndi.rmi.registry.RegistryContext#lookup

com.sun.jndi.rmi.registry.RegistryContext#decodeObject

javax.naming.spi.NamingManager#getObjectInstance

org.apache.aries.jndi.OSGiObjectFactoryBuilder#getObjectInstance

org.apache.aries.jndi.ObjectFactoryHelper#getObjectInstance

org.apache.aries.jndi.ObjectFactoryHelper#getObjectInstanceViaContextDotObjectFactories

 

protected Object getObjectInstanceViaContextDotObjectFactories(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment, Attributes attrs) throws Exception {

  Object result = null;

  String factories = (String)environment.get("java.naming.factory.object");

 

  if (factories != null && factories.length() > 0) {

    String[] candidates = factories.split(":");

    ClassLoader cl = (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {

          public ClassLoader run() {

            return Thread.currentThread().getContextClassLoader();

          }

    });

 

    for (String cand : candidates) {

      ObjectFactory factory = null;

      try {

        Class<ObjectFactory> clz = cl.loadClass(cand);

        factory = (ObjectFactory)clz.newInstance();

      } catch (Exception e) {

        if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Exception instantiating factory: " + e);

      }

 

      if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "cand=" + cand + " factory=" + factory);

 

      if (factory != null) {

        if (factory instanceof DirObjectFactory) {

          if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "its a DirObjectFactory");  

          DirObjectFactory dirFactory = (DirObjectFactory)factory;

          result = dirFactory.getObjectInstance(obj, name, nameCtx, environment, attrs);

        }

        else {

          if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "its an ObjectFactory");  

          result = factory.getObjectInstance(obj, name, nameCtx, environment);

        }  

      }

 

      if (result != null && result != obj)

        break;

    }

  }  if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "result = " + result);

  return (result == null) ? obj : result;

}

我們可以看到,getObjectInstanceViaContextDotObjectFactories()將會調(diào)用getObjectInstance的任意ObjectFactory類,其中一個(gè)跟我們Gadget鏈相關(guān)的類就是WSIFServiceObjectFactory。

CVE-2020-4450-snippet-4.java:

public Object getObjectInstance(Object obj, Name name, Context context, Hashtable env) throws Exception {

  Trc.entry(this, obj, name, context, env);

  if (obj instanceof Reference && obj != null) {

    Reference ref = (Reference)obj;

    if (ref.getClassName().equals(WSIFServiceRef.class.getName())) {

      String wsdlLoc = resolveString(ref.get("wsdlLoc"));

      String serviceNS = resolveString(ref.get("serviceNS"));

      String serviceName = resolveString(ref.get("serviceName"));

      String portTypeNS = resolveString(ref.get("portTypeNS"));

      String portTypeName = resolveString(ref.get("portTypeName"));

      if (wsdlLoc != null) {

        WSIFServiceFactory factory = WSIFServiceFactory.newInstance();

        WSIFService service = factory.getService(wsdlLoc, serviceNS, serviceName, portTypeNS, portTypeName);

        Trc.exit(service);

        return service;

      }  

    } else if (ref.getClassName().equals(WSIFServiceStubRef.class.getName())) {

      String wsdlLoc = resolveString(ref.get("wsdlLoc"));

      String serviceNS = resolveString(ref.get("serviceNS"));

      String serviceName = resolveString(ref.get("serviceName"));

      String portTypeNS = resolveString(ref.get("portTypeNS"));

      String portTypeName = resolveString(ref.get("portTypeName"));

      String preferredPort = resolveString(ref.get("preferredPort"));

      String className = resolveString(ref.get("className"));

      if (wsdlLoc != null) {

        WSIFServiceFactory factory = WSIFServiceFactory.newInstance();

        WSIFService service = factory.getService(wsdlLoc, serviceNS, serviceName, portTypeNS, portTypeName); // <----

        Class iface = Class.forName(className, true, Thread.currentThread().getContextClassLoader());

        Object stub = service.getStub(preferredPort, iface);

        Trc.exit(stub);

        return stub;

      }  

    }  

  }

}

針對getObjectInstance()的調(diào)用將會根據(jù)一個(gè)指向遠(yuǎn)程XML定義的URL來初始化一個(gè)Web服務(wù)調(diào)用框架(WSIF)服務(wù),而這個(gè)XML也是攻擊者可控的。在這種場景下,服務(wù)的className會被設(shè)置為javax.el.ELProcessor,并且會定義一個(gè)java:operation元素,然后將findByPrimaryKey()映射為eval()方法。

getObjectInstance()調(diào)用將會返回一個(gè)WSIFClientProxy Java代理對象,當(dāng)findByPrimaryKey()方法被調(diào)用時(shí),這個(gè)代理對象將會調(diào)用ELProcessor實(shí)例的eval()方法。別忘了我們已經(jīng)可以通過反序列化來控制this.key參數(shù)了,那么這樣一來,我們就可以通過表達(dá)式語言注入技術(shù)來實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行了。

信息披露漏洞(CVE-2020-4449)

這個(gè)漏洞利用Gadget利用的是一個(gè)XXE漏洞,漏洞代碼如下所示。

CVE-2020-4450-snippet-5.java:

public static Definition readWSDL(String contextURL, String wsdlLoc) throws WSDLException {

  Trc.entry(null, contextURL, wsdlLoc);

   

  initializeProviders();

   

  WSDLFactory factory = WSDLFactory.newInstance("org.apache.wsif.wsdl.WSIFWSDLFactoryImpl");

   

  WSDLReader wsdlReader = factory.newWSDLReader(); // <---------------------

  wsdlReader.setFeature("javax.wsdl.verbose", false);

  try {

    Definition def = wsdlReader.readWSDL(contextURL, wsdlLoc); // <---------

    Trc.exitExpandWsdl(def);

    return def;

  } catch (WSDLException e) {

    Trc.exception(e);

    MessageLogger.log("WSIF.0002E", wsdlLoc);

    throw e;

  }  

}

這個(gè)Gadget還演示了如何在現(xiàn)代JRE中如何繞過類似的緩解方案,尤其是通過FTP來實(shí)現(xiàn)越界提取等等。在這種場景下,數(shù)據(jù)是通過錯(cuò)誤信息來提取的,因此當(dāng)代碼在解析XML文檔時(shí),如果沒有封裝在一個(gè)try/catch語句中的話,那么該漏洞將產(chǎn)生嚴(yán)重影響。

漏洞修復(fù)

為了修復(fù)這些漏洞,IBM采取了很多措施來確保TxServerInterceptor類不再會被反序列化為任意對象:

 怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞

到此,相信大家對“怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI