vlambda博客
学习文章列表

CVE-2020-4450: WebSphere远程代码执行漏洞分析


报告编号:B6-2020-080601

报告来源:360CERT

更新日期:2020-08-06

0x01 漏洞简述

2020年06月08日,360CERT监测到 IBM官方发布了 WebSphere远程代码执行 的风险通告,该漏洞编号为 CVE-2020-4450,漏洞等级:严重,漏洞评分:9.8分

此漏洞由IIOP协议上的反序列化造成,未经身份认证的攻击者可以通过IIOP协议远程攻击WebSphere Application Server,在目标服务端执行任意代码,获取系统权限,进而接管服务器。

对此,360CERT建议广大用户及时安装最新补丁,做好资产自查以及预防工作,以免遭受黑客攻击。

0x02 风险等级

360CERT对该漏洞的评定结果如下

评定方式 等级
威胁等级 严重
影响面 广泛
360CERT评分 9.8分

0x03 影响版本

  • WebSphere Application Server: 9.0.0.0 to 9.0.5.4

  • WebSphere Application Server: 8.5.0.0 to 8.5.5.17

  • WebSphere Application Server: 8.0.0.0 to 8.0.0.15

  • WebSphere Application Server: 7.0.0.0 to 7.0.0.45

0x04 漏洞详情

iiop触发反序列化

按照zdi给出的分析,iiop的拦截是在com.ibm.ws.Transaction.JTS.TxServerInterceptor#receive_request,那么下断点进行远程调试,由于websphere自己实现了一套iiop,所以想要走到iiop触发反序列化的点还需要构造满足条件的iiop客户端,这里需要走到demarshalContext方法,前提是满足validOtsContexttrue,也就是需要serviceContext不为null
CVE-2020-4450: WebSphere远程代码执行漏洞分析

CVE-2020-4450: WebSphere远程代码执行漏洞分析

假如我们已经构造了serviceContext不为null,继续往下看,将serviceContext.context_data传入demarshalContext方法。
调用createCDRInputStream创建CDRInputStream,实际上生成的是EncoderInputStreamCDRInputStream的子类,之后调用EncoderInputStream#read_any方法。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

之后的调用有些繁琐,就不列出来了,调用栈为:
CVE-2020-4450: WebSphere远程代码执行漏洞分析

serviceContext赋值

由于需要serviceContext不为null,才能走到demarshalContext方法体里面,在com.ibm.rmi.iiop.Connection#setConnectionContexts方法中,该方法如下:
CVE-2020-4450: WebSphere远程代码执行漏洞分析
setConnectionContexts方法可以对ServiceContext属性进行设置,但是我们需要从iiop生成的默认上下文中获取存储着的当前Connection信息。

参考@iswin师傅的文章,可以知道,在com.ibm.rmi.iiop.GIOPImpl里,存在一个getConnection方法,可以获取当前上下文的Connection实例对象,

CVE-2020-4450: WebSphere远程代码执行漏洞分析

不过该方法需要传递当前ior参数,而GIOPImpl的对象在orb里,
CVE-2020-4450: WebSphere远程代码执行漏洞分析

这些都能通过反射从defaultContext中获取。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

恶意数据流构造

看一下数据流是怎么被解包的,具体在demarshalContext方法里,也就是构造完ServeicContext下一步要执行的。

CVE-2020-4450: WebSphere远程代码执行漏洞分析

与之对应的,marshalContext方法里有相应的数据包生成代码,所以只需要将关键代码单独掏出来,再把PropagationContext对象构造一下,就能生成gadgets对象的数据流。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
构造的关键代码为:
CVE-2020-4450: WebSphere远程代码执行漏洞分析

gadgets

既然iiop已经通了,那么我们就根据zdi给出的gadgets进行构造,首先需要明确的是,反序列化的入口是org.apache.wsif.providers.ejb.WSIFPort_EJB(因为websphere自身类加载器的问题,导致现有的gadgets都无法利用,所以我们只能基于新的挖掘的类来构造gadgets)。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
这里我们利用的是handle.getEJBObject方法,handle是一个Handle类型,在实现了Handle接口的类中,能够进行利用的是com.ibm.ejs.container.EntityHandle这个类,事实上,我们在对handle进行赋值的时候,比较复杂,需要反射多个对象。

我们来看一下他的getEJBObject方法。
这里有几处需要注意的:
CVE-2020-4450: WebSphere远程代码执行漏洞分析

lookup加载本地factory

先来看第一处,也就是lookup方法,这里的homeJNDIName是我们在反序列化流程中可以控制的。于是,在能够出网的情况下,可以指向我们的rmi服务。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
这里首先会调用registry.lookup,获取我们在rmibind的对象,由于jdk版本过高的原因,所以导致com.sun.jndi.ldap.object.trustURLCodebase选项默认被设置为false,也就是说,我们不能利用jndi去远程服务器上利用URLClassLoader动态加载加载类,只能实例化本地的Factory,这里利用的方式是加载本地类,具体细节参考:Exploiting JNDI Injections in Java。

简单来说,正常情况下,jndi的利用会在RegistryImpl_Stub.lookup之后返回一个ReferenceWrapper的客户端代理类,ReferenceWrapper提供了三个参数,className,factory,factoryLocation,如果本地加载不到className,那么就会去factoryLocation上加载factory,大致流程为:

CVE-2020-4450: WebSphere远程代码执行漏洞分析

而现在不能远程去加载factoryLocation,那么我们寻求一个本地factory来实例化,并利用该factorygetObjectInstance方法,根据zdi提供的漏洞细节,满足条件的factoryorg.apache.wsif.naming.WSIFServiceObjectFactory

CVE-2020-4450: WebSphere远程代码执行漏洞分析

前边的调用栈是这样的,

com.sun.jndi.rmi.registry.RegistryContext#lookup
com.sun.jndi.rmi.registry.RegistryContext#decodeObject
javax.naming.spi.NamingManager#getObjectInstance

rmi服务端可以在reference对象里对factory进行设置,当然这个factory需要满足一些条件,当调用WSIFServiceObjectFactory.getObjectInstance,我们看一下这个方法。这里wsdlLoc,serviceNS等值都可以在rmi端通过Reference进行设置。

CVE-2020-4450: WebSphere远程代码执行漏洞分析

这里会对ref进行判断,也就是Reference对象的第一个参数,也是可控的。我们需要走到下面的判断里,也就是让refWSIFServiceStubRef,原因是这样的,需要回过来看到前面,
我们需要指定返回代理的类型是EJBHome。这里有两个地方需要指定接口的类型,一个是narrow第二个参数homeClass,一个是在Reference指定className,用来控制返回的代理类型。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

WSIF web服务

这里的getObjectInstance调用将从远程URL初始化WSIF服务,该URL指向可由攻击者控制的远程XML定义,在远程xml里,我们可以将方法进行映射,这里只说个概念,后面再仔细说。

指定生成的stub的接口类型

refWSIFServiceStubRef类型的时候,可以通过className来指定生成stub的接口类型,这样就能生成实现EJHome接口的代理,这里前面已经提到过了,具体在rmi服务端通过Reference进行设置。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

创建动态代理

这里会在getStub里创建代理类。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
根据提供的接口,最终返回WSIFClientProxy代理类。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

el表达式注入

接着,在this.findFindByPrimaryKey获取homeClass接口的findByPrimaryKey方法。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
之后,就会调用动态代理类的invke方法,传入findFindByPrimaryKeythis.key,也就是方法的参数。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
WSIFClientProxy.invoke的方法里,会调用WSIFPort实现类的createOperation方法。
CVE-2020-4450: WebSphere远程代码执行漏洞分析
这个createOperation方法就能将方法进行映射,这里我们可以将findFindByPrimaryKey方法映射为本地存在的方法,比如javax.el.ELProcessoreval方法,这里的映射就主要体现在之前提到的WSIF web服务里,需要将映射内容体现在我们自定义的远程xml文件里。主要语法可以参考:WSDL Java Extension(https://ws.apache.org/wsif/providers/wsdl_extensions/java_extension.html),具体的调用就在自定义rmi服务上进行设置,之后的调用栈如下:
CVE-2020-4450: WebSphere远程代码执行漏洞分析
最终在ELProcessor#eval方法里执行el表达式。

漏洞利用

利用成功的截图如下:
CVE-2020-4450: WebSphere远程代码执行漏洞分析

版本修复

在官网下载补丁(https://www.ibm.com/support/pages/node/6220276)进行分析,发现对反序列化入口WSIFPort_EJB进行了修改,在readObject方法里,将原本的handle.getEJBObject方法给取消了,这样,也就把这个链的入口给杀死了。
CVE-2020-4450: WebSphere远程代码执行漏洞分析

0x05 时间线

2020-06-04  IBM发布预警

2020-06-08  360CERT发布预警

2020-07-21  ZDI发布分析报告

2020-08-05  360CERT发布分析报告

0x06 参考链接

1.CVE-2020-4450: WebSphere远程代码执行漏洞通告

https://cert.360.cn/warning/detail?id=f11756f5eb2722da048a0aecb5592a1c

2.HubL中的EL注入导致远程代码执行

https://xz.aliyun.com/t/3605

3.ABUSING JAVA REMOTE PROTOCOLS IN IBM WEBSPHERE

https://www.thezdi.com/blog/2020/7/20/abusing-java-remote-protocols-in-ibm-websphere

4.Websphere CVE-2020-4450漏洞分析

5.Exploiting JNDI Injections in Java

https://www.veracode.com/blog/research/exploiting-jndi-injections-java

6.WSDL Java Extension

https://ws.apache.org/wsif/providers/wsdl_extensions/java_extension.html


推荐阅读:

1、

2、

3、

注:360CERT官方网站提供《CVE-2020-4450: WebSphere远程代码执行漏洞分析》完整详情,点击阅读原文