Lucene search

K
attackerkbAttackerKBAKB:20B41B3B-C3B7-4103-8752-4E9A011B6CA9
HistoryMar 25, 2022 - 12:00 a.m.

CVE-2022-1040

2022-03-2500:00:00
attackerkb.com
221

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.971 High

EPSS

Percentile

99.7%

An authentication bypass vulnerability in the User Portal and Webadmin allows a remote attacker to execute code in Sophos Firewall version v18.5 MR3 and older.

Recent assessments:

jbaines-r7 at April 15, 2022 7:28pm UTC reported:

On March 25, 2022, Sophos published a critical security advisory for Sophos Firewall. The advisory details CVE-2022-1040, an authentication bypass issue affecting the firewall’s User Portal and Webadmin web interfaces. The bypass allows a remote and unauthenticated attacker to execute arbitrary code, resulting in a CVSSv3 score of 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).

Sophos has reported this vulnerability was “being used to target a small set of specific organizations primarily in the South Asia region.” There is no other public reporting confirming attempted public exploitation of this issue. No public proof of concept currently exists.

Although Sophos Firewall is fairly widely deployed (Shodan fingerprints ~50,000 instances of User Portal and ~1500 Webadmin), wide exploitation of this issue is unlikely. By default, Sophos Firewall automatically updates, and no public proof of concept exists. Both of these factors should keep exploitation down to a minimum.

The Patch

Sophos introduced two changes to address this vulnerability. This first was a change to web.xml to introduce a new filter on all requests.

albinolobster@ubuntu:~$ diff -u sophos_unpatched/webconsole/WEB-INF/web.xml sophos_patched/webconsole/WEB-INF/web.xml 
--- sophos_unpatched/webconsole/WEB-INF/web.xml	2022-03-28 10:57:23.841991165 -0700
+++ sophos_patched/webconsole/WEB-INF/web.xml	2022-03-28 10:41:47.757727685 -0700
@@ -12,6 +12,16 @@
 	</session-config>
 
 	<filter>
+        	<filter-name>RequestCheckFilter</filter-name>
+	        <filter-class>cyberoam.sessionmanagement.RequestCheckFilter</filter-class>
+	</filter>
+
+	<filter-mapping>
+	        <filter-name>RequestCheckFilter</filter-name>
+	        <url-pattern>/*</url-pattern>
+	</filter-mapping>
+
+	<filter>
 		<filter-name>SessionCheckFilter</filter-name>
 		<filter-class>cyberoam.sessionmanagement.SessionCheckFilter</filter-class>
 	</filter>

The second change was the introduction of the new filter RequestCheckFilter.class. The entire class is a bit long to fit here, but the interesting part for an unauthenticated attacker follows:

JSONObject jsonObject = null;
String mode = httpRequest.getParameter("mode");
String operation = httpRequest.getParameter("operation");
String dataGridId = httpRequest.getParameter("datagridid");
try {
  CyberoamLogger.debug("RequestCheckFilter", "mode: " + mode);
  CyberoamLogger.debug("RequestCheckFilter", "operation: " + operation);
  CyberoamLogger.debug("RequestCheckFilter", "dataGridId: " + dataGridId);
  if (request.getParameter("json") != null && mode != null) {
    operation = (operation == null) ? "0" : operation;
    dataGridId = (dataGridId == null) ? "0" : dataGridId;
    if (ALL_SESSION_CHECK_EXEMPTED_MODES.contains(Integer.valueOf(Integer.parseInt(mode))) || 
      isFilterRequired(Integer.parseInt(mode), 
        Integer.parseInt(operation), 
        Integer.parseInt(dataGridId))) {
      jsonObject = new JSONObject(httpRequest.getParameter("json"));
      if (!isvalidJSONKeys(jsonObject)) {
        redirectToLogin(httpRequest, httpResponse);
        return;
      } 
    } 
  } else {
    CyberoamLogger.debug("RequestCheckFilter", "JSON parameter not found in request payload");
  } 
  chain.doFilter((ServletRequest)httpRequest, (ServletResponse)httpResponse);

I’m going to skip over talking about all of the mode, operation, and datagrid values as it just complicates things. Generically, this logic examines the request’s HTTP parameters to determine if it needs to pass the attacker provided JSON into a method called isValidJSONKeys. Which looks like this:

private boolean isvalidJSONKeys(JSONObject jsonObject) {
    Iterator<?> jsonkeys = jsonObject.keys();
    while (jsonkeys.hasNext()) {
      String key = (String)jsonkeys.next();
      if (!isAsciiPrintable(key)) {
        CyberoamLogger.info("RequestCheckFilter", "JSON key with non-ASCII printable characters!  key = " + key);
        return false;
      } 
    } 
    return true;
}

This method is obviously looping over the keys in the attacker-provided JSON and validating the keys are made up of printable ASCII characters.

An unauthenticated and remote “attacker” can hit this code path relatively easily with a curl:

albinolobster@ubuntu:~/sophos_patched$ curl -v --insecure -H "X-Requested-With: XMLHttpRequest" -X POST 'https://10.0.0.19/userportal/Controller?mode=8700&operation=1&datagrid=179&json=\{"🦞":"test"\}'
*   Trying 10.0.0.19:443...
* Connected to 10.0.0.19 (10.0.0.19) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=NA; ST=NA; L=NA; O=NA; OU=NA; CN=Appliance_Certificate_n7Rmy46scKRgK16; [email protected]
*  start date: Aug  1 00:00:00 2015 GMT
*  expire date: Dec 31 23:59:59 2036 GMT
*  issuer: C=NA; ST=NA; L=NA; O=NA; OU=NA; CN=Default_CA_n7Rmy46scKRgK16; [email protected]
*  SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> POST /userportal/Controller?mode=8700&operation=1&datagrid=179&json={"🦞":"test"} HTTP/1.1
> Host: 10.0.0.19
> User-Agent: curl/7.74.0
> Accept: */*
> X-Requested-With: XMLHttpRequest
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Fri, 15 Apr 2022 14:59:50 GMT
< Server: xxxx
< X-Frame-Options: SAMEORIGIN
< Strict-Transport-Security: max-age=31536000
< X-Content-Type-Options: nosniff
< Content-Length: 15
< Cache-Control: max-age=2592000
< Expires: Sun, 15 May 2022 14:59:50 GMT
< Connection: close
< 
{"status":400}
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, close notify (256):

Note the {"status":400} response from the server. An unpatched server will respond a little differently:

albinolobster@ubuntu:~/sophos_patched$ curl --insecure -H "X-Requested-With: XMLHttpRequest" -X POST 'https://10.0.0.12/userportal/Controller?mode=8700&operation=1&datagrid=179&json=\{"🦞":"test"\}'
{"status":"Session Expired"}

Since the patch induces a new response from the firewall, we can remotely detect patch status. You can try the same thing on the Webadmin interface and it too generates a slightly different response ({"status":"-2"} when unpatched).

Finally, it might be useful to know that exploitation attempts on a patched server generate the following log in /log/tomcat.log.

2022-04-15 15:59:50,877:INFO:RequestCheckFilter - URI: /userportal/Controller
2022-04-15 15:59:50,877:INFO:RequestCheckFilter - JSON key with non-ASCII printable characters!  key = 🦞

Summary

In order to address CVE-2022-1040, Sophos introduced a fairly small patch to filter the JSON content of some HTTP requests. Exploitation attempts will have non-ascii characters in the request’s json parameter’s JSON keys. If your Sophos Firewall is internet facing, it should absolutely have automatic update enabled (the default behavior). If you are in a situation where you can’t do that, you likely shouldn’t be using the internet facing features.

Assessed Attacker Value: 2
Assessed Attacker Value: 2Assessed Attacker Value: 2

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.971 High

EPSS

Percentile

99.7%