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_debug
为true
查看jdwp
的端口号
IDEA
的DEBUG
配置如下
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
Weblogic的请求都会经过securedExecute
,跟进doSecuredExecute
函数。
weblogic.servlet.internal.WebAppServletContext#doSecuredExecute
这里会使用checkAccess
对请求进行权限检查。
weblogic.servlet.security.internal.WebAppSecurity#checkAccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, boolean, boolean)
继续跟进重载的checkAccess
函数。
weblogic.servlet.security.internal.WebAppSecurity#checkAccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, boolean, boolean, boolean)
一个三元表达式,checkAllResources
在调用时硬编码为false
,此时直接调用getConstraint
函数。
weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(javax.servlet.http.HttpServletRequest)
可以也为重载调用,看到参数为getRelativeURI(req)
weblogic.servlet.security.internal.WebAppSecurity#getRelativeURI
weblogic.servlet.internal.ServletRequestImpl#getRelativeUri
最终参数为/css/%2E%2E%2Fconsole.portal
,此时的payload
经过http
传输导服务器后自动解码一次了。
weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(java.lang.String, java.lang.String)
这里this.constraintsMap.get("")
赋值的consForAllMethods
类型为ServletMapping
且内容为:
这个Mapping
从哪里来得呢,其实是servlet
配置文件里写好的,文件位置:
/wls12213/wlserver/server/lib/consoleapp/webapp/WEB-INF/web.xml
也就是说符合配置文件的URL都不需要鉴权,接着调用consForAllMethods.get(relURI)
,这里传入的为/css/%2E%2E%2Fconsole.portal
。
weblogic.servlet.utils.ServletMapping#get
跟进父类StandardURLMapping
的get
函数
weblogic.servlet.utils.StandardURLMapping#get
一路跟进
weblogic.servlet.utils.StandardURLMapping#getExactOrPathMatch
一路跟进
weblogic.utils.collections.MatchMap#match
可以看到在Mapping里最终匹配的为/css/
,并且unrestricted
为true
,最终层层返回并赋值给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
根据变量值判断进入isAuthorized
函数。
weblogic.servlet.security.internal.SecurityModule#isAuthorized
继续跟进checkAccess
weblogic.servlet.security.internal.ChainedSecurityModule#checkAccess
请求的URL不是以/j_security_check
结尾,因此进入checkUserPerm
weblogic.servlet.security.internal.CertSecurityModule#checkUserPerm
一路判断,然后进入hasPermission
函数
weblogic.servlet.security.internal.WebAppSecurity#hasPermission
这里cons
不为null
,因此开关调用isUnrestricted
函数
weblogic.servlet.security.internal.ResourceConstraint#isUnrestricted
这里其实就是判断内容为true
的unrestricted
,这里就不会被后台定向到登录,并最终层层向上返回true
通过校验。
http://127.0.0.1:7001/console/css/%252E%252E%252Fconsole.portal
即可访问后台conolse。
绕过权限校验之后开始请求分发
12.2.1.3.0_debug/weblogic_jar/com.oracle.weblogic.servlet.2020111012033377144.jar!/weblogic/servlet/internal/WebAppServletContext.class:1917
参数中包含requestFacade.getServletStub(req)
并跟进
weblogic.servlet.internal.ServletObjectsFacadeImpl#getServletStub
继续跟进getServletStub
函数
weblogic.servlet.internal.ServletRequestImpl#getServletStub
最终返回sstub
成员作为参数并创建ServletStubImpl
的action
,查看该action
内容
这个具体的action
是怎么来的呢,同样是根据上面提到的web.xml
文件获取的。
/css/%2E%2E%2Fconsole.portal
因为.portal
结尾会匹配到AppManagerServlet
这个servlet-name
,查看具体的servlet
会使用AsyncInitServlet
,且初始化参数为MBeanUtilsInitSingleFileServlet
weblogic.servlet.AsyncInitServlet#service
跟进到AsyncInitServlet
类,查看具体内容:
delegate
成员为MBeanUtilsInitSingleFileServlet
类,跟进service
函数。
com.bea.netuix.servlets.manager.UIServlet#doPost
跟进到createUIContext
函数
com.bea.netuix.servlets.manager.UIServlet#createUIContext
com.bea.netuix.servlets.manager.UIServletInternal#createUIContext
跟进getTree
函数
com.bea.netuix.servlets.manager.UIServletInternal#getTree
可以看到这里再次进行了一次URL解码,相当于目录穿越,最终请求为/console.portal
并传入processStream
函数。
接着跟入一些系列的导航初始化中
com.bea.console.utils.BreadcrumbBacking#init
从这里开始接受恶意参数,跟入findFirstHandle
函数
com.bea.console.utils.BreadcrumbBacking#findFirstHandle
此时从参数中取出恶意字符串并返回。
com.bea.console.handles.HandleFactory#getHandle
加载com.tangosol.coherence.mvel2.sh.ShellSession
类,然后传入java.lang.Runtime.getRuntime().exec('calc.exe');""
作为参数并实例化,完成远程代码执行。
https://paper.seebug.org/1395/#cve-2020-14882
本文作者:Rai4over
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/145903.html