Weblogic 10.3.6.0版本 Console HTTP 协议远程代码执行漏洞(CVE-2020-14882)分析以及poc构造
2020-11-10 10:50:52 Author: xz.aliyun.com(查看原文) 阅读量:445 收藏

在Oracle官方发布的2020年10月关键补丁更新公告CPU中,包含一个存在于Weblogic Console中的高危远程代码执行漏洞CVE-2020-14882。该漏洞与CVE-2020-14883权限绕过漏洞配合,可以使得攻击者在未经身份验证的情况下执行任意代码并接管WebLogic Server Console。

在这篇文章中,我们首先来看看CVE-2020-14882代码执行漏洞。而后续下一篇文章,我将深入的分析下CVE-2020-14883权限绕过漏洞,并说明二者是如何配合使用的。

CVE-2020-14882

首先我们来研究下Weblogic Console HTTP协议远程代码执行漏洞。这个漏洞影响范围广:影响范围包含了Oracle Weblogic Server10.3.6.0.0、12.1.3.0.0、12.2.1.3.0、12.2.1.4.0、14.1.1.0.0这几个版本。

网上关于这个漏洞的分析报告,多数是以Weblogic12版本展开的,10版本与12版本下的漏洞触发点相同点,但利用链不同。所以我在这里就拿Weblogic 10.3.6.0.0版本,对这个漏洞进行分析。

按照惯例,我们从CVE-2020-14882相关漏洞细节入手,看看能不能还原出poc。

关于CVE-2020-14882的漏洞详情如下:

“结合 CVE-2020-14883 漏洞,远程攻击者可以构造特殊的 HTTP请求,在未经身份验证的情况下接管 WebLogic Server Console ,并在 WebLogic Server
Console 执行任意代码。”

从描述上来看,CVE-2020-14883是权限绕过漏洞,而CVE-2020-14882是后台代码执行漏洞。我们要是想利用CVE-2020-14882。因此我们可以得到如下两个信息:

  1. 攻击是通过向后台发送HTTP请求实现的

  2. CVE-2020-14882须要有后台管理员权限

在此之外,我们还通过一些披露可以知道:

本次漏洞实际执行点位于com/bea/console/handles/HandleFactory.class中的getHandle方法下图红框处

下面我们就试着还原一下这个漏洞:

首先我们先以后台管理员的身份,访问一下后台地址

http://localhost:7001/console/console.portal?_nfpb=true&_pageLabel=HomePage1

在我们的请求发送到Weblogic服务器后,程序会执行到com/bea/console/utils/BreadcrumbBacking.class,并调用其中init方法,见下图

BreadcrumbBacking翻译过来大概是面包屑导航支持的意思。从笔者的理解来看,上图这里应该是Weblogic用来解析传入的url的作用。

我们继续看init方法

public void init(HttpServletRequest req, HttpServletResponse res) {
    if (req.getParameter(NO_BC) == null) {

...

        String handleStr = this.findFirstHandle(req);
        if (this.handle == null && handleStr != null && !handleStr.equals("")) {
            try {
                this.handle = HandleFactory.getHandle(handleStr);
                String name = this.handle.getDisplayName();
                req.getSession().setAttribute(BREADCRUMB_CONTEXT_VALUE, name);
            } catch (Exception var6) {
            }
        }

        this.dispatchedValue = (BCValue)req.getSession().getAttribute(DISPATCHED_BREADCRUMB);
    }
}

上面节选了init方法中的一块代码片段,为什么要节选这个片段呢?原因很简单:这块代码段里多次出现了”Handle”字眼,这意味着代码涉及到从请求(req)中获取与Handle相关的操作。而代码中也存在着”HandleFactory.getHandle(handleStr);”

回顾上文,本次漏洞实际执行点不正是位于com/bea/console/handles/HandleFactory.class中的getHandle方法中吗?

看来漏洞入口被我们找到了,下面来看看怎么建立一条从url到漏洞入口的道路,重点分析如下代码

从上图可见,如果想执行69行的this.handle = HandleFactory.getHandle(handleStr);进入漏洞触发点,首先要满足67行的this.handle == null && handleStr != null && !handleStr.equals("")条件

而String类型的handleStr变量是从66行处的this.findFirstHandle(req)获取到的看看weblogic如何从请求中获取handle

public String findFirstHandle(HttpServletRequest request) {
        String handle = null;
        Enumeration parms = request.getParameterNames();

        while(parms.hasMoreElements()) {
            String parmName = (String)parms.nextElement();
            String parm = request.getParameter(parmName);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Looking at parameters = " + parmName);
                if (parmName.toLowerCase().indexOf("password") == -1 && parm.toLowerCase().indexOf("password") == -1) {
                    LOG.debug("Looking at parm value = " + parm);
                } else {
                    LOG.debug("Looking at parm value = ************");
                }
            }

            if (this.currentUrl.getParameter(parmName) == null) {
                this.currentUrl.addParameter(parmName, parm);
            }

            if (parmName.indexOf(REQUEST_CONTEXT_VALUE) != -1) {
                handle = parm;
            }
        }

        return handle;
    }

findFirstHandle方法将会遍历请求中所有参数名以及参数值,随后通过如下代码判断参数名是否为”
handle”,代码如下:

if (parmName.indexOf(REQUEST_CONTEXT_VALUE) != -1) {

    handle = parm;

}

这里的REQUEST_CONTEXT_VALUE值为”handle”,见下图:

当请求参数中有名为handle的参数时,findFirstHandle会将该参数的值进行返回。我们动态调试一下,看看分析的对不对,构造如下url:

http://localhost:7001/console/console.portal?_nfpb=true&_pageLabel=HomePage1&handle=熊本熊本熊

可见findFirstHandle将”熊本熊本熊”字符串返回

回到init方法中,findFirstHandle将返回的url中handle参数值传递给handleStr变量,见下图66行

handleStr变量进入67行if分支,并传递给漏洞执行点getHandle方法中

getHandle方法中代码如下:

public static Handle getHandle(String serializedObjectID) {
        if (StringUtils.isEmptyString(serializedObjectID)) {
            throw new InvalidParameterException("No serialized object string specified");
        } else {
            serializedObjectID = serializedObjectID.replace('+', ' ');
            String serialized = HttpParsing.unescape(serializedObjectID, "UTF-8");
            int open = serialized.indexOf(40);
            if (open < 1) {
                throw new InvalidParameterException("Syntax error parsing serializedObjectID string: " + serialized);
            } else {
                String className = serialized.substring(0, open);
                String objectIdentifier = serialized.substring(open + 2, serialized.length() - 2);

                try {
                    Class handleClass = Class.forName(className);
                    Object[] args = new Object[]{objectIdentifier};
                    Constructor handleConstructor = handleClass.getConstructor(String.class);
                    return (Handle)handleConstructor.newInstance(args);
                } catch (ClassNotFoundException var8) {
                    throw new InvalidParameterException("No handle class found for type: " + className);
                } catch (Exception var9) {
                    throw new InvalidParameterException("Unable to instanciate handle type: " + className, var9);
                }
            }
        }
    }

其实这里的内容很简单,让我们换一个poc,大家就会很清晰的了解getHandle的功能以及为什么可以造成代码执行漏洞。我们这里更换的poc如下:

http://localhost:7001/console/console.portal?_nfpb=true&_pageLabel=HomePage1&handle=java.lang.String("kumamon.fun")

此时传入getHandle的变量为String类型的字符串:java.lang.String("kumamon.fun"),见下图

接着getHandle方法判断字符串中左括号“(”的位置。(左括号ascii码值为40),见下图

紧接着,通过左括号位置,获取className以及objectIdentifier

这里className为字符串:java.lang.String而objectIdentifier为字符串kumamon.fun

接着程序做了三件事情:

  1. 通过className获取对应的Class对象

  2. 将String类型的objectIdentifier存入 Object[]数组中

  3. 获取该类的带String类型参数的构造方法

最后,程序调用该带String类型参数的构造方法,实例化一个对象

漏洞触发点到此已经分析结束了。回顾上文,当我们构造一个如下url时:

http://localhost:7001/console/console.portal?_nfpb=true&_pageLabel=HomePage1&handle=a("b")

Weblogic将会调用a方法的带String类型参数的构造方法,并将b字符串传入执行

那么我们怎么样才能找到这样一个利用链呢?需要满足恶意类中存在带String类型参数的构造方法、且该构造方法中存在着可以利用的地方,使得我们构造的字符串传入后可以顺利的执行。

POC

不得不说,Weblogic的漏洞往往有着关联,比如说CVE-2019-2725,这个漏洞当时遇到的payload的条件与这次的几乎一样,在CVE-2019-2725漏洞中,廖新喜给出了一个无视jdk版本限制的利用链:

com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext

http://xxlegend.com/2019/04/30/CVE-2019-2725%E5%88%86%E6%9E%90/

但廖大神并没有给出具体的利用方式。详细的Poc构造以及利用可以参考我的这篇文章:

https://kumamon.fun/CVE-2020-14882/

里面利用到的利用链即为:

com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext 这条

于此同时,com.bea.core.repackaged.springframework.context.support.ClassPathXmlApplicationContext

与FileSystemXmlApplicationContext相同,都是继承了AbstractXmlApplicationContext类,因此ClassPathXmlApplicationContext这条也是可用的

写在最后

本来想将CVE-2020-14882、CVE-2020-14883放到一篇文章中来介绍,但奈何CVE-2020-14883这个漏洞中内容也挺多的,放在一块文章太长了。写的多不如写的细,因此把他们分开成为两个文章。

后续关于FileSystemXmlApplicationContext这条利用链是如何构造的,我也想写一篇文章详细的谈谈,希望大家喜欢。


文章来源: http://xz.aliyun.com/t/8470
如有侵权请联系:admin#unsafe.sh