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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.