WebLogic CVE-2020-2551漏洞分析

一、前言

2020年1月15日,Oracle发布了一系列的安全补丁,其中Oracle WebLogic Server产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行远程代码。

image-20200219153352047

 

经过分析这次漏洞主要原因是错误的过滤JtaTransactionManager类,JtaTransactionManager父类AbstractPlatformTransactionManager在之前的补丁里面就加入到黑名单列表了,T3协议使用的是resolveClass方法去过滤的,resolveClass方法是会读取父类的,所以T3协议这样过滤是没问题的。但是IIOP协议这块,虽然也是使用的这个黑名单列表,但不是使用resolveClass方法去判断的,这样默认只会判断本类的类名,而JtaTransactionManager类是不在黑名单列表里面的,它的父类才在黑名单列表里面,这样就可以反序列化JtaTransactionManager类了,而JtaTransactionManager类是存在jndi注入的。

二、漏洞复现

1

在本地虚拟机上面就成功执行poc了

image-20200219162305165

三、漏洞分析

根据官网漏洞描述及上面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对象。

IDL-1

RMI-IIOP

以前,Java程序员不得不在RMI和CORBA / IIOP(Java IDL)之间进行选择,以用于分布式编程解决方案。现在,通过遵守一些限制,RMI服务器对象可以使用IIOP协议并与以任何语言编写的CORBA客户端对象进行通信。此解决方案称为RMI-IIOP。RMI-IIOP将RMI风格的易用性与CORBA跨语言互操作性相结合。

rmiiiop1a

oracle官网的RMI-IIOP的例子 ,为了方便IDEA编辑器DEBUG调试我把官网例子稍改了一下,并把客户端和服务端分开存储。

先创建这三个公用的类

2

3

4

编写服务端并把上面这三个java文件拷贝到一个java项目里面

5

image-20200225162409812

 

直接启动HelloServer的main方法会在target目录编译好代码

image-20200225162733882

在项目的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方法即可启动成功

image-20200225163611662

在创建一个新的客户端项目去启动客户端代码.

6

 

启动步骤和服务端步骤除了不执行orbd命令其它步骤都一样.

image-20200225174444888

用wireshark抓包看下image-20200225170321525

传输的数据中没有aced魔术头,这里不是使用ObjectOutputStream序列化的数据。在客户端和服务端开始位置都DEBUG看下。

先列出客户端的调用栈

7

_HelloInterface_Stub这个class是执行rmic -iiop命令生成的

image-20200225181953641

sayHello方法会从request中获取数据,然后执行CDROutputStream.write_value方法会执行到IIOPOutputStream.invokeObjectWriter方法

image-20200225183532424

这里反射调用Message.writeObject方法,方法参数属性是IIOPOutputStream类型,这也解释了为什么前面抓包数据中没有aced魔术头。

下面是服务端的调用栈

8

服务端也是利用rmic命令生成_HelloImpl_Tie的class

image-20200225195300394

HelloImpl_Tie有一个invoke方法,读取流中的数据去执行CDRInputStream.read_value方法。然后会执行IIOPInputStream.invokeObjectReader方法,这个方法会反射执行Message.readObject方法,参数属性也是IIOPInputStream类型。

image-20200225194750086

到这里就可以理解了,RMI-IIOP协议中使用IIOPOutputStream去序列化数据,字节流与ObjectOutputStream序列化数据不太一样。

发送poc看下weblogic调用链.

9

断点几个关键的地方

image-20200225215049402

_NamingContextAnyImplBase.invoke方法中请求类型是bind_any,对应var5的值为0,会执行var2.read_any(),var2的值是IIOPInputStream.

image-20200225222029705

会去执行AnyImpl.read_value方法

image-20200225222518956

image-20200225222456307

var2.kind().value()值是29会执行IIOPInputStream.read_value方法。

image-20200225222900389

var14是JtaTransactionManager对象,var13是JtaTransactionManager类的序列化描述符,会执行ValueHandlerImpl.readValue方法

image-20200225223629106

image-20200225224017034

这里var2是ObjectStreamClass类,var1是JtaTransactionManager对象,var6是JtaTransactionManager对象输入流数据,会执行ObjectStreamClass.readObject方法

image-20200225225217751

这里会反射调用,JtaTransactionManager.readObject方法。

image-20200225225427339

image-20200225225754608

image-20200225225620301

调试到这里就明白了,那看下weblogic怎么修复的。

image-20200225230339471

下载并安装此补丁后,在发送poc会提示。

image-20200226101310597

断点看下这里

image-20200227190955658

image-20200226101516792

image-20200226101649829

可以看到JtaTransactionManager父类AbstractPlatformTransactionManager在黑名单列表里面,第一个断点处verifyClassPermitted方法的for循环会循环判断父类,所以会抛出黑名单异常警告。

 

 

 

 

Written by