CVE-2020-14882&CVE-2020-14883
2020年的洞了,但是关于这两个漏洞的分析也没有很多,老洞新学,从我自己的角度来看这个漏洞,拒绝当文章搬运工,希望你能从中学到不一样的东西
不会搭建debug环境的同学请参考
https://cloud.tencent.com/developer/article/1608010
CVE-2020-14882权限绕过
此处是一处权限绕过漏洞,其根本触发的核心逻辑用一句话概括:在经过权限校验之后又进行了一次url解码,导致URL编码绕过
0X01:权限校验
权限校验的入口在weblogic.servlet.internal.WebAppServletContext#doSecuredExecute中
jar包叫com.oracle.weblogic.servlet.jar

在此处下断点,此处代码是在WebAppServletContext#doSecuredExecute方法中的,checkAccess方法中就判定了该次请求路由是否是有权限访问的

此处的checkAccess有两个重载,在调试的时候请把断点下到这个函数上

在他之前调用的checkAccess是这个,在它上面,但是分析的时候可能是因为反编译的原因单步在这个checkAccess的时候并不能正常,但是会跳转到另一个checkAccess也就是上面的这个checkAccess上

这个影响不大,那我们就接着上面的继续分析,直接进入isAuthorized方法

然后又调用了checkAccess方法

在这个里面接着调用了CertSecurityModle的checkUserPerm方法

在这个里面调用我们的hasPermission方法,也就是在这个里面,判断了路由是否应该被允许访问,可能很多人会好奇前面这么多代码,那些代码有什么用处?其实不用关心那些代码,因为此时我发出的是一个默认环境下,正常的请求,并没有添加附加参数以及改变其他的配置,在这种默认配置下去分析这个的解析请求,跟着断点我们找到了他解析权限的逻辑,那么我们之后只改变url也肯定能来到这个逻辑,不受其他代码的影响
此处需要注意他的第四个参数,cons,这个参数等等会讲到

可以看到此处是判断了cons的unrestricted的值,如果该值为true,那么我们就返回true,权限校验通过

那么这个cons是哪儿来的呢?
还记得刚刚么,刚刚问到了这个cons是干嘛的,那我们追溯这个cons

往上追溯第一次:
CertSecurityModule#checkUserPerm函数的第四个参数

往上追溯第二次:
ChainedSecurityMoudle#checkUserPerm函数的第四个参数

往上追溯第三次:
SecurityModuel#isAuthorized的第三个参数

往上追溯第四次:
发现源头是WebAppSecurity中通过this.getConstraint()得来的

我们重新断点,进入这个getConstraint中一探究竟,跟进这个consForAllMethods.get

此处this.strictPattern为true,进入super.get

可以看到此处调用getExactOrPathMatch对我们的path(请求的url做了判断),跟进

对我们的url进行了匹配,是否为允许访问的资源

此处的匹配只要满足、这个map里面的,就可以通过


如果此处校验不通过,那么就会返回null

如果此处校验通过,那么就会返回value,而一个我们校验通过的url的路由是这样的

也就是说,我们的路由只要是为允许的map中的的值就能绕过,网上的payload是
/console/css/%252E%252E/console.portal
其实也可以是
/console/common/%252E%252E/console.portal
/console/images/%252E%252E/console.portal
等……

至于为什么要2次编码,因为我们在请求的时候会自动进行一次url解码,那么我们到时候这个样子的
发包:

在进入getConstraint方法时会调用他的一个重载

在里面调用getRelativeUri返回相对路径,../就这样被解析掉了

那么来到我们权限校验的地方就是这个样子,为null,自然就不可行了

经过2次编码后的是这个样子的,在权限校验时仍然保留一层url编码,得以绕过

那么绕过了权限校验,但是此时我们的url仍然是一个url编码的状态,那么在什么地方解码的呢?
来到解析请求的地方
UIServlet#service

我们是get方法,进入doget,但是doget调用了dopost

doPost里面经过一系列调用,最终调用到getTree,在getTree中会再次调用urldecode

到了doPost,我们其实就来到了我们的第二个漏洞CVE-2020-14883命令执行的开始的地方了,第一个漏洞的权限绕过到这里其实就结束了,因为鉴权部分以及绕过,后面都是一些静态资源的读取,能看到一些前端样式,但是由于这个权限绕过仅仅是从url上欺骗了一下weblogic,真正的操作同样是没有权限干不了的,这也就是为什么权限绕过的payload只能看一些前端样式不能做任何操作,也没有任何数据
CVE-2020-14883命令执行
紧跟着上面我们来到了doPost方法,刚刚我们Url二次解码是发生在createContext中的,现在我们完成了createContext,继续往下执行来到runLifecycle方法

继续往下到lifecycle.run

紧接着就会进入BreadrumBacking#init方法,我们关注到这个地方的两个方法,其中this.findFristHandle(req)的作用是取出第一个参数handle的值,然后将这个值放入HandleFactory.getHandle中

我们跟进findFristHandle,不难发现此处是一个循环,循环所有的参数,当参数为handle的时候返回handle的值,也就是说我们的payload只需要传参handle就行了,并不需要像网上的payload一般传递一些无用的值
网上的payload:
1 | http://127.0.0.1:7001/console/console.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession("java.lang.Runtime.getRuntime('calc');"); |
实际的payload:
1 | http://127.0.0.1:7001/console/css/%252e%252e%252fconsole.portal?handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc%27);%22) |
并不需要_nfpb,_pageLabel这两个参数

返回handle的值后进入HandleFactory.getHandle
可以看到1获取了字符(在字符串中的位置,在2处进行切分,所以获得了3处的类路径,在4处使用反射加载该类并在低5处获得该类的String类型的构造函数执行,当目标类被实例化的时候,触发构造函数。

也就是说这时我们就需要找一个内置的类,他的String构造函数可以执行我们的代码“java.lang.Runtime.getRuntime().exec(‘calc’)”
这个时候恰巧就有这么一个类,那就是
com.tangosol.coherence.mvel2.sh.ShellSession
我们来看看他的构造函数,非常简单,直接调用exec执行
