您好,登錄后才能下訂單哦!
本篇內(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類。
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()方法來獲取嵌入的對象類。
盡管我們可以實(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)。
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)用。
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。
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í)行了。
這個(gè)漏洞利用Gadget利用的是一個(gè)XXE漏洞,漏洞代碼如下所示。
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ù)這些漏洞,IBM采取了很多措施來確保TxServerInterceptor類不再會被反序列化為任意對象:
到此,相信大家對“怎么濫用IBM WebSphere平臺中的Java遠(yuǎn)程協(xié)議漏洞”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(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)容。