An image about a critical authentication bypass vulnerability CVE-2023-51467 in Apache OfBiz.

SonicWall Discovers Critical Apache OFBiz Zero-day -AuthBiz

SonicWall is committed to helping provide defenders with the necessary resources to protect their organizations. As part of this effort, our threat researchers discovered and responsibly disclosed CVE-2023-51467.

By

Update 1/2/24

According to our sensor network, SonicWall is seeing a large number of exploitation attempts of CVE-2023-51467. We highly recommend upgrading to Apache OFBiz version 18.12.11 or newer.

Overview

SonicWall Capture Labs threat research team has discovered an Authentication Bypass vulnerability being tracked as CVE-2023-51467 with a CVSS score of 9.8. It was discovered while researching the root cause for the previously disclosed CVE-2023-49070. The security measures taken to patch CVE-2023-49070 left the root issue intact and therefore the authentication bypass was still present.

Apache OfBiz is an open-source Enterprise Resource Planning (ERP) system. It may seem unfamiliar, but as part of the software supply chain it has a wide install base in prominent software, such as Atlassian’s JIRA (used by over 120K companies). As a result, like with many supply chain libraries, the impact of this vulnerability could be severe if leveraged by threat actors. Our research demonstrates that this flaw could lead to the exposure of sensitive information or even the ability to execute arbitrary code as demonstrated in the short video below using version 18.12.10, where the system “ping” application is executed by an unauthenticated attacker.

SonicWall is committed to helping provide defenders with the necessary resources to protect their organizations. As part of this effort, we responsibly disclosed the discovered vulnerability to Apache OFBiz providing them advanced noticed with the intent that patches or other mitigation strategies can be deployed. We advise anyone using Apache OFbiz to update to version 18.12.11 or newer immediately.  In addition to the patch, SonicWall has developed IPS signature IPS:15949 to detect any active exploitation of this vulnerability.

Technical Analysis and Discovery

We were intrigued by the chosen mitigation when analyzing the patch for CVE-2023-49070 and suspected the real authentication bypass would still be present since the patch simply removed the XML RPC code from the application. As a result, we decided to dig into the code to figure out the root cause of the auth-bypass issue. As anticipated, the root issue was in the login functionality. We focused our analysis on the LoginWorker.java file in order to understand the flow of data within the various functions and checks during the authentication process.

This led us to run a couple of testcases which we have outlined below to examine the authentication functionality using Apache OFbiz version 18.12.09. For testing, we started by using the publicly available poc1 and poc2 for CVE-2023-49070.

Testcase 1

Our first test case was based on using empty USERNAME and PASSWORD parameters while including the parameter requirePasswordChange=Y in URI This test was derived from the testing of CVE-2023-49070 during our signature development to ensure detection in all use cases.  The question was posed, what if there is no username and password in the request? For instance, the request might look like https[:]//www.example.com:8443/webtools/control/xmlrpc/?USERNAME=&PASSWORD=&requirePasswordChange=Y.

In this testcase (lines #437 to #448 from the LoginWorker.java file), the login function returns the value requirePasswordChange due to username and password being empty, and requirePasswordChange set to ‘Y’ as seen in the code snippet in Figure 1.

List<String> unpwErrMsgList = new LinkedList<String>();
if (UtilValidate.isEmpty(username)) {
unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, “loginevents.username_was_empty_reenter”, UtilHttp.getLocale(request)));
}
if (UtilValidate.isEmpty(password) && UtilValidate.isEmpty(token)) {
unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, “loginevents.password_was_empty_reenter”, UtilHttp.getLocale(request)));
}
boolean requirePasswordChange = “Y”.equals(request.getParameter(“requirePasswordChange”));
if (!unpwErrMsgList.isEmpty()) {
request.setAttribute(“_ERROR_MESSAGE_LIST_”, unpwErrMsgList);
return requirePasswordChange ? “requirePasswordChange” : “error”;
//return value depends on the requirePasswordChange parameter
}

Figure 1: Login function when empty username and password is provided

Subsequently, the given return value from the function login is passed to the checkLogin function. Unexpectedly, the flow doesn’t enter in the conditional block shown in Figure 2 due to the boolean checks (username == null) and (password == null) returning false even though both the parameters are empty or blank. Additionally, the “error”.equals(login(request, response)) also holds false due to the return value given by login function was requirePasswordChange.

if (userLogin == null) {
// check parameters
username = request.getParameter(“USERNAME”);
password = request.getParameter(“PASSWORD”);
token = request.getParameter(“TOKEN”);
// check session attributes
if (username == null) username = (String) session.getAttribute(“USERNAME”);
if (password == null) password = (String) session.getAttribute(“PASSWORD”);
if (token == null) token = (String) session.getAttribute(“TOKEN”);// in this condition log them in if not already; if not logged in or can’t log in, save parameters and return error
if (username == null
|| (password == null && token == null) // This condition is getting checked.
|| “error”.equals(login(request, response))) {

Figure 2: Code responsible to verify the empty username/password

As a result, the checkLogin function ends up returning success, allowing the authentication to be bypassed.

Testcase 2

In this testcase, we attempted to authenticate with a known invalid USERNAME and PASSWORD parameter with the parameter requirePasswordChange set equal to ‘Y’ This testcase is derived from the original public poc for CVE-2023-49070  and used to further our understanding of how the authentication process works.  For instance, the request would look like, https[:]//www.example.com:8443/webtools/control/xmlrpc/?USERNAME=x&PASSWORD=y&requirePasswordChange=Y.

In this scenario, lines #601 to #605 from the LoginWorker.java file in the login function return the value requirePasswordChange due to the parameter requirePasswordChange=Y as seen in the code snippet in Figure 3.

} else {
Map<String, String> messageMap = UtilMisc.toMap(“errorMessage”, (String) result.get(ModelService.ERROR_MESSAGE));
String errMsg = UtilProperties.getMessage(resourceWebapp, “loginevents.following_error_occurred_during_login”, messageMap, UtilHttp.getLocale(request));
request.setAttribute(“_ERROR_MESSAGE_”, errMsg);
return requirePasswordChange ? “requirePasswordChange” : “error”;
}

Figure 3: Code responsible for return value when non-empty username and password

Subsequently, the given return value from the function login is passed to the checkLogin function. Here, the flow didn’t enter in the conditional block in Figure 2 due to username and password not being null. Additionally, the “error”.equals(login(request, response)) also held false due to the return value given by login function was requirePasswordChange, similar to testcase 1.

Hence, the checkLogin function returns success, allowing the authentication to be bypassed.

Conclusion

Considering the above result, it can be concluded that the requirePasswordChange=Y, the magic string, is causing the authentication to be bypassed regardless of the username and password field or other parameters.  As a result, removing the XML RPC code was not an effective patch and the bypass remained.

Patch Review

The vulnerability was fixed swiftly (Kudos!) by the Apache OFbiz  with commit d8b097f and ee02a33.  For due diligence, we confirmed the patch was effective by running the same two testcases.

Verification of Testcase 1

In this scenario, the lines #436 to #446 in the function login still returns requirePasswordChange, but now there is an added utilization of the function UtilValidate.isEmpty. This comes into play on lines #341 to #343 in the function checkLogin as seen in the code snippet in Figure 4.

if (UtilValidate.isEmpty(username)
|| (UtilValidate.isEmpty(password) && UtilValidate.isEmpty(token))
|| “error”.equals(login(request, response))) {

Figure 4: Use of UtilValidate.isEmpty function to verify empty values

Here, boolean checks UtilValidate.isEmpty(username) and UtilValidate.isEmpty(password) return true, unlike (username == null) and (password == null), before resulting in the code returning the value error within the checkLogin function.

This prevents the authentication bypass from occurring and confirms testcase 1 has been patched.

Verification of Testcase 2

In this scenario, the lines #609 to #614 in the function login return in contrast to requirePasswordChange before the patch as seen in Figure 5.

} else {
Map<String, String> messageMap = UtilMisc.toMap(“errorMessage”, (String) result.get(ModelService.ERROR_MESSAGE));
String errMsg = UtilProperties.getMessage(RESOURCE, “loginevents.following_error_occurred_during_login”,
messageMap, UtilHttp.getLocale(request));
request.setAttribute(“_ERROR_MESSAGE_”, errMsg);
return “error”;
}

Figure 5: Code changes to return error in case of error during login

This leads to return true by the boolean check “error”.equals(login(request, response)) in the checkLogin function conditional block seen in Figure 4. This ends up returning the value error by the checkLogin function preventing the authentication bypass.

Acknowledgement

We appreciate the prompt response and remediation by the Apache OFBiz team. They demonstrated extreme care for the security of their customers and were a pleasure to work with.

Hasib Vhora
Senior Threat Researcher | SonicWall
Hasib Vhora is a Senior Threat Researcher at SonicWall, where his focus is to identify, analyze and mitigate critical vulnerabilities. His primary role is to actively monitor zero days and novel threats by keeping an eye on the Open-Source Threat Intelligence (OSINT) space using various methods including leveraging the power of automation. Hasib is a seasoned vulnerability researcher, specializing in the development of protection signatures in Intrusion Prevention Systems (IPS) and Web Application Firewalls (WAF).