Overview

In an effort to safeguard our customers, we perform proactive vulnerability research with the goal of identifying zero-day vulnerabilities that are likely to impact the security of leading organizations. Recently, we were looking at the list of available OVA appliances from SonicWall and identified the WXA appliance image was available for download. We decided to configure the appliance and take a quick look at it to determine if it would be a worthwhile vulnerability research target. Within about an hour of setting up the appliance and performing an initial enumeration, we identified a chain of vulnerabilities which we could leverage to achieve arbitrary code execution as the root user account.

The root of the vulnerability lies in the fact that the appliance exposes a dispatcher web service that leverages a hardcoded secret key to authenticate users invoking the API interface. An attacker that has reverse engineered the dispatcher service can recover this hard coded secret key and leverage it to authenticate to the service on all other instances of the WXA appliance.

After successfully authenticating to the WXA appliance, we identified an endpoint that allowed for argument injection when the wget command was invoked. This vulnerability provided the attacker an arbitrary file write primitive, allowing the attacker to write arbitrary files anywhere on the system as the root user account. Praetorian leveraged this primitive to override the dig binary at /usr/bin/dig and then invoked a separate endpoint, which shelled out to the dig command to achieve arbitrary code execution as the root user account.

Application Architecture Review

We reviewed the SonicWall WXA appliance and identified a Java process running as root which ran the dispatcher service. This service listens on port 54321/TCP using the FastCGI protocol (See Figure 1). This service is not directly accessible from the appliance. However, we identified an instance of lighttpd that was configured to forward requests to /wanopt/dispatch (the dispatcher service listening on port 54321/TCP) using the FastCGI protocol (See Figure 2).

Figure 1: We observed the dispatcher service was running as the root user account and was configured to listen on port 54321/TCP.

Figure 2: We observed that lighttpd was configured to forward requests to /wanopt/dispatch to the dispatcher service listening on port 54321/TCP using the FastCGI protocol.

Bypassing Authentication using a Hardcoded Secret

We examined the authentication logic the dispatcher service implemented, and observed that when the dispatcher service received a request it would make a call to the isAuthorizedRequest function to perform an authentication check as shown in Figure 3.

Figure 3: The dispatcher service when it received a new request would make a call to the isAuthorizedRequest function to perform an authentication check.

We decided to dig further into the isAuthorizedRequest function and identified a call to SSOKey.getResponseHeader, which was invoked with an Authorization header specified in the request. The authorization header also had to contain the keyword “SNWL” (See Figure 4).

Figure 4: We analyzed the isAuthorizedRequest function and determined that it would invoke the getResponseHeader function to perform an authentication check using data from the Authorization header in the client request.

We then analyzed the getResponseHeader function and identified a hard coded secret of “somethingnew”, which was leveraged in a call to the “createSSOKey” function using a hash and rand value that appeared to be retrieved from the Authorization header (See Figure 5).

Figure 5: We observed that the getResponseHeader function leveraged a hardcoded secret key of “somethingnew”, which the user-supplied rand value uses to compute a hash value.

We observed that the parseAuthorizationHeaderHash and parseAuthorizationHeaderRead functions read two variables from the Authorization header named rand and hash (See Figure 6).

Figure 6: The code leveraged to extract the rand and hash values from the Authorization header.

We then observed that the rand value was leveraged with the hardcoded secret in a call to the createSSOKey function. The resulting function computed an MD5 hash of the concatenation of the hardcoded secret with the rand value in the header (see Figure 7).

Figure 7: We observed that the createSSOKey function computed an MD5 hash of the hard coded secret value concatenated with the rand value specified with the header and compared this output to the hash value specified within the header.

We then computed a valid hash value based on a rand value of 1337 and the hard coded secret of “somethingnew” we had retrieved from the source code, and the hash value ultimately allowed us to bypass authentication requirements (See Figure 8).

Figure 8: We manually computed a valid hash value for a rand value of 1337 and verified that this allowed us to bypass authentication within the dispatcher service.

Achieving Remote Code Execution

We began examining the post-authentication attack surface of the application and identified an endpoint which invoked the wget parameter with an attacker-controlled URL. This endpoint was vulnerable to argument injection, which allowed an attacker to control both the downloaded data and the path on the disk where the data would be written. We leveraged the argument injection issue to overwrite the /usr/bin/dig utility on disk with malicious code which created a root bindshell on the system (See Figures 9 and 10).

Figure 9: The source code of the webRequest action in the wpstats module which contained an argument injection vulnerability.

Figure 10: An example malicious request which could be leveraged to overwrite the /usr/bin/dig utility with an attacker-controlled binary.

Finally, we invoked the dig action within the interfaceStatus module, which invoked the now malicious dig utility as the root user on the system (See Figure 11, 12, and 13).

Figure 11: We identified an endpoint which invoked the dig command as root when invoked.

Figure 12: We invoked the dig action in the interfaceStatus module which then launched our now malicious /usr/bin/dig binary as the root user on the system.

Figure 13: We then connected to the newly created bindshell spawned by our malicious version of the dig utility to gain full root privileges on the system.

Reporting the Vulnerability

Our team promptly reported the vulnerability to SonicWall and learned that the vendor considers the WXA appliance to be end of life and that making the appliance available for download on the website was a mistake (see Figure 14). However, SonicWall did add us to their product security hall of fame for the high quality and in-depth nature of the writeup we provided to them on the WXA appliance image vulnerability.

SonicWall WXA Vendor Response

Figure 14: We were informed by the SonicWall PSIRT team that this product was considered end-of-life and that they removed the download for the appliance from the web portal.

SonicWall WXA Hall of Fame

Figure 15: We were added to the SonicWall product security hall of fame for the vulnerability we reported.

Conclusion

While the impact of this vulnerability is quite low in terms of real-world risk potential, we thought it was an interesting case study on the dangers of leveraging hard-coded secrets for authentication. Additionally, we thought this highlighted some potential design considerations that developers should keep in mind when building applications. It’s likely that SonicWall leveraged this configuration to simplify the integration of the WXA appliance with the NSA appliance without requiring arduous steps to setup authentication between these two systems. However, leveraging hardcoded authentication keys or secrets that are distributed as part of the application binary shipped to end-users is almost always a bad idea in terms of security.