On July 11, 2023, Rapid7 and Adobe disclosed CVE-2023-29298, an access control bypass vulnerability affecting ColdFusion, which Rapid7 had reported to Adobe in April 2023. The vulnerability allows an attacker to bypass the product feature that restricts external access to the ColdFusion Administrator. Rapid7 and Adobe believed that CVE-2023-29298 was fixed upon publishing our coordinated disclosure (Rapid7 explicitly noted in our disclosure that we had not tested the patch Adobe released).
Upon review of the patch for CVE-2023-29298 as found in ColdFusion 2021 Update 8 (2021.0.08.330144), Rapid7 discovered that the patch released on July 11 does not successfully remediate the original issue and can be bypassed by an attacker. Adobe assigned CVE-2023-38205 to the patch bypass and has issued a complete fix as of July 19, 2023.
Rapid7 has observed exploitation of CVE-2023-29298 in the wild in multiple customer environments. Our team published a blog with observations and guidance for customers on July 17. We have validated that the new patch released July 19 fully remediates the issue.
The following products are vulnerable to CVE-2023-38205:
This issue was discovered by Stephen Fewer, a Principal Security Researcher at Rapid7, and is being disclosed in accordance with Rapid7's vulnerability disclosure policy.
Adobe provided the following statement to Rapid7:
"Adobe recommends updating ColdFusion installations to the latest release. Please see APSB23-47 for more information. Adobe is aware that CVE-2023-38205 has been exploited in the wild in limited attacks targeting Adobe ColdFusion."
The July 11 patch for CVE-2023-29298 modifies the vulnerable method IPFilterUtils.checkAdminAccess
to use a new helper method Utils.canonicalizeURI
to transform a URL into its canonical form before performing the access control, as shown below.
private static final String[] RESTRICTED_INTERNAL_PATHS = new String[] { "/restplay", "/cfide/restplay", "/cfide/administrator", "/cfide/adminapi", "/cfide/main", "/cfide/componentutils", "/cfide/wizards", "/cfide/servermanager", "/cfide/lockdown" };
public static void checkAdminAccess(HttpServletRequest req) {
String uri = Utils.getServletPath(req);
uri = Utils.canonicalizeURI(uri.toLowerCase()); // <----
for (String restrictedPath : RESTRICTED_INTERNAL_PATHS) {
if (uri.startsWith(restrictedPath)) {
String ip = req.getRemoteAddr();
if (!isAllowedIP(ip))
throw new AdminAccessdeniedException(ServiceFactory.getSecurityService().getAllowedAdminIPList(), ip);
break;
}
}
}
The method Utils.canonicalizeURI attempts to remove sequences of characters such as duplicate forward slashes, double dot notation and redundant dot path segments in a URLs path, as shown below.
public static String canonicalizeURI(String uri) {
if (uri == null || uri.length() == 0)
return uri;
uri = uri.replace('\\', '/');
uri = trimDuplicateSlashes(uri);
uri = collapseDotDots(uri); // <----
uri = trimTrailingDotsSpacesNull(uri);
if (uri.charAt(0) == '.')
uri = uri.substring(1);
uri = substitute(uri, "/./", "/");
if (uri.endsWith("/."))
uri = uri.substring(0, uri.length() - 2);
if (uri.length() == 0)
uri = "/";
return uri;
}
Of note is the method Utils.collapseDotDots, which will remove all path segments that contain a double dot along with the preceding path segment. For example, if a URL path has the string “/hello/../world/” then the method Utils.collapseDotDots would correctly transform this string into “/world/” by deleting the character sequence “/hello/..” via a call to StringBuffer.delete as shown below.
public static String collapseDotDots(String str) {
if (str.indexOf("/..") == -1)
return str;
StringBuffer sb = new StringBuffer(str);
int i;
while ((i = str.indexOf("/..")) != -1) {
int segmentStart = str.lastIndexOf('/', i - 1);
sb.delete(segmentStart, i + 3); // <----
str = sb.toString();
}
if (str.length() == 0)
str = "/";
return str;
}
The method Utils.canonicalizeURI
attempts to remove sequences of characters such as duplicate forward slashes, double dot notation and redundant dot path segments in a URLs path, as shown below.
public static String canonicalizeURI(String uri) {
if (uri == null || uri.length() == 0)
return uri;
uri = uri.replace('\\', '/');
uri = trimDuplicateSlashes(uri);
uri = collapseDotDots(uri); // <----
uri = trimTrailingDotsSpacesNull(uri);
if (uri.charAt(0) == '.')
uri = uri.substring(1);
uri = substitute(uri, "/./", "/");
if (uri.endsWith("/."))
uri = uri.substring(0, uri.length() - 2);
if (uri.length() == 0)
uri = "/";
return uri;
}
Of note is the method `Utils.collapseDotDots`, which will remove all path segments that contain a double dot along with the preceding path segment. For example, if a URL path has the string `“/hello/../world/”` then the method `Utils.collapseDotDots` would correctly transform this string into `“/world/”` by deleting the character sequence `“/hello/..”` via a call to `StringBuffer.delete` as shown below.
public static String collapseDotDots(String str) {
if (str.indexOf("/..") == -1)
return str;
StringBuffer sb = new StringBuffer(str);
int i;
while ((i = str.indexOf("/..")) != -1) {
int segmentStart = str.lastIndexOf('/', i - 1);
sb.delete(segmentStart, i + 3); // <----
str = sb.toString();
}
if (str.length() == 0)
str = "/";
return str;
}
While the above is correct, it exposes an issue in how ColdFusion handles ColdFusion Modules (CFM) and ColdFusion Component (CFC) endpoints when resolving a path to the endpoint. If an attacker accesses a URL path of “/hax/..CFIDE/wizards/common/utils.cfc”
the access control can be bypassed and the expected endpoint can still be reached, even though it is not a valid URL path (Note, there is no expected forward slash after the double dot and before CFIDE).
Upon processing this path, the method Utils.collapseDotDots
will transform the path to “cfide/wizards/common/utils.cfc”
by removing the double dot path segment and the preceding segment “/hax/..”. The path “cfide/wizards/common/utils.cfc”
will not be matched against any of the restricted paths in RESTRICTED_INTERNAL_PATHS during IPFilterUtils.checkAdminAccess
because it no longer begins with a leading forward slash. This bypasses the access control. However, the underlying Servlet will still process the path “/hax/..CFIDE/wizards/common/utils.cfc”
, allowing the expected CFC endpoint to be called. The same is true for CFM endpoints.
The following was tested on Adobe ColdFusion 2021 Update 8 (2021.0.08.330144) running on Windows Server 2022 and configured with the Production and Secure profiles.
We can demonstrate the patch bypass by using the cURL command. For example when attempting to perform a remote method call wizardHash on the /CFIDE/wizards/common/utils.cfc
endpoint, the following cURL command can be used — note the use of double dot notation as highlighted below:
Note: The ampersand (&) has been escaped with a caret (^) as this example is run from Windows, on Linux you must escape the ampersand with a forward slash (\).
c:\> curl -ivk --path-as-is http://172.25.25.0:8500/hax/..CFIDE/wizards/common/utils.cfc?method=wizardHash^&inPassword=foo
We can see that both the access control and the patch for CVE-2023-29298 have been bypassed and the request completed successfully.
Adobe released a fix for this vulnerability on July 19, 2023. The following versions remediate the issue, per Adobe’s advisory:
Since Rapid7 has observed exploitation in the wild, we strongly recommend ColdFusion customers update to the latest versions as soon as possible, without waiting for a typical patch cycle to occur.