在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的漏洞详情如下:

1
2
“结合 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方法下图红框处

337c31913917cad0ba284a2c3f35d4fc.png

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

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

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

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

4ac9666365bfc98564be4cd91de43805.png

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

我们继续看init方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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到漏洞入口的道路,重点分析如下代码

b25e91462b4994c165ba0d678d4bc1d7.png

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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”,代码如下:

1
2
3
4
5
if (parmName.indexOf(REQUEST_CONTEXT_VALUE) != -1) {

handle = parm;

}

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

59ece6b0005427a66bfaeed26e13dab1.png

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

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

26c733411771d6d3b7213a21eb37a046.png

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

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

427e12f6c22a8ccb953521ac06d2ff9d.png

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

getHandle方法中代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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”),见下图

35ddc015a8b2deb9a9809b46c2a3857f.png

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

0be72a36dbd1638822c43a7c05d3815f.png

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

3a9f5620e9e459c287958cf754780547.png

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

接着程序做了三件事情:

698d79a1d772b6b0916f38db05d79b9a.png

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

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

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

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

84d53abd6ffa717c23a1e140cef89675.png

漏洞触发点到此已经分析结束了。回顾上文,当我们构造一个如下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 这条

a5771d8a2b3650d45648e2d743bb0c5f.png

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

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

8b0786bd524d4951164bc0a0a1a95525.png

写在最后

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

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