WebLogic CVE-2020-2551漏洞分析
一、前言
2020年1月15日,Oracle发布了一系列的安全补丁,其中Oracle WebLogic Server产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行远程代码。
经过分析这次漏洞主要原因是错误的过滤JtaTransactionManager类,JtaTransactionManager父类AbstractPlatformTransactionManager在之前的补丁里面就加入到黑名单列表了,T3协议使用的是resolveClass方法去过滤的,resolveClass方法是会读取父类的,所以T3协议这样过滤是没问题的。但是IIOP协议这块,虽然也是使用的这个黑名单列表,但不是使用resolveClass方法去判断的,这样默认只会判断本类的类名,而JtaTransactionManager类是不在黑名单列表里面的,它的父类才在黑名单列表里面,这样就可以反序列化JtaTransactionManager类了,而JtaTransactionManager类是存在jndi注入的。
二、漏洞复现
在本地虚拟机上面就成功执行poc了
三、漏洞分析
根据官网漏洞描述及上面poc中可以知道 主要是利用IIOP协议进行的攻击。在分析之前先了解下这些协议的概念
根据oracle官网的文档
RMI
使用RMI,您可以使用Java编程语言编写分布式程序。RMI易于使用,您不需要学习单独的接口定义语言(IDL),并且可以获得Java固有的“编写一次,随处运行”的好处。客户端,远程接口和服务器完全用Java编写。RMI使用Java远程方法协议(JRMP)进行远程Java对象通信。 RMI缺少与其他语言的互操作性,因为它不使用CORBA-IIOP作为通信协议。
IIOP,CORBA和Java IDL
IIOP是CORBA的通信协议,使用TCP / IP作为传输方式。它指定了客户端和服务器通信的标准。CORBA是由对象管理组(OMG)开发的标准分布式对象体系结构。远程对象的接口以平台无关的接口定义语言(IDL)描述。实现了从IDL到特定编程语言的映射,将语言绑定到CORBA / IIOP。 Java SE CORBA / IIOP实现称为Java IDL。与IDlj 编译器一起,Java IDL可用于从Java编程语言定义,实现和访问CORBA对象。
RMI-IIOP
以前,Java程序员不得不在RMI和CORBA / IIOP(Java IDL)之间进行选择,以用于分布式编程解决方案。现在,通过遵守一些限制,RMI服务器对象可以使用IIOP协议并与以任何语言编写的CORBA客户端对象进行通信。此解决方案称为RMI-IIOP。RMI-IIOP将RMI风格的易用性与CORBA跨语言互操作性相结合。
oracle官网的RMI-IIOP的例子 ,为了方便IDEA编辑器DEBUG调试我把官网例子稍改了一下,并把客户端和服务端分开存储。
先创建这三个公用的类
编写服务端并把上面这三个java文件拷贝到一个java项目里面
直接启动HelloServer的main方法会在target目录编译好代码
在项目的target/classes目录下执行rmic命令生成服务端和客户端的代理类
rmic -iiop org.example.HelloImpl
上面的命令会创建以下文件
_HelloImpl_Tie.class 用于服务端
_HelloInterface_Stub.class 用户客户端
启动服务端
windows系统执行 -> start orbd -ORBInitialPort 1050
linux系统执行 -> orbd -ORBInitialPort 1050 &
用IDEA编辑器直接启动HelloServer的main方法即可启动成功
在创建一个新的客户端项目去启动客户端代码.
启动步骤和服务端步骤除了不执行orbd命令其它步骤都一样.
传输的数据中没有aced魔术头,这里不是使用ObjectOutputStream序列化的数据。在客户端和服务端开始位置都DEBUG看下。
先列出客户端的调用栈
_HelloInterface_Stub这个class是执行rmic -iiop命令生成的
sayHello方法会从request中获取数据,然后执行CDROutputStream.write_value方法会执行到IIOPOutputStream.invokeObjectWriter方法
这里反射调用Message.writeObject方法,方法参数属性是IIOPOutputStream类型,这也解释了为什么前面抓包数据中没有aced魔术头。
下面是服务端的调用栈
服务端也是利用rmic命令生成_HelloImpl_Tie的class
HelloImpl_Tie有一个invoke方法,读取流中的数据去执行CDRInputStream.read_value方法。然后会执行IIOPInputStream.invokeObjectReader方法,这个方法会反射执行Message.readObject方法,参数属性也是IIOPInputStream类型。
到这里就可以理解了,RMI-IIOP协议中使用IIOPOutputStream去序列化数据,字节流与ObjectOutputStream序列化数据不太一样。
发送poc看下weblogic调用链.
断点几个关键的地方
_NamingContextAnyImplBase.invoke方法中请求类型是bind_any,对应var5的值为0,会执行var2.read_any(),var2的值是IIOPInputStream.
会去执行AnyImpl.read_value方法
var2.kind().value()值是29会执行IIOPInputStream.read_value方法。
var14是JtaTransactionManager对象,var13是JtaTransactionManager类的序列化描述符,会执行ValueHandlerImpl.readValue方法
这里var2是ObjectStreamClass类,var1是JtaTransactionManager对象,var6是JtaTransactionManager对象输入流数据,会执行ObjectStreamClass.readObject方法
这里会反射调用,JtaTransactionManager.readObject方法。
调试到这里就明白了,那看下weblogic怎么修复的。
下载并安装此补丁后,在发送poc会提示。
断点看下这里
可以看到JtaTransactionManager父类AbstractPlatformTransactionManager在黑名单列表里面,第一个断点处verifyClassPermitted方法的for循环会循环判断父类,所以会抛出黑名单异常警告。
本文来源于Lonely Blog -全球网络安全资讯平台, 转载请注明出处: https://blog.wuhao13.xin/1817.html