This is an automated email from the ASF dual-hosted git repository.
jleroux pushed a commit to branch release18.12
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/release18.12 by this push:
new 6c00877a14 Improved: [SECURITY] (CVE-2024-36104) Path traversal
leading to RCE (OFBIZ-13092)
6c00877a14 is described below
commit 6c00877a14fa4c0c85cad6b12c34a4762c61ead0
Author: Jacques Le Roux <[email protected]>
AuthorDate: Sat Jan 18 10:11:14 2025 +0100
Improved: [SECURITY] (CVE-2024-36104) Path traversal leading to RCE
(OFBIZ-13092)
Using allowedTokens was a bad idea (when all you have is a (new!) hammer,
everything looks like a nail).
It came to my mind that I already used StringEscapeUtils::unescapeHtml4
in several places and in this case it's the tool of choice.
Actually I thought about it when beginning, but was unsure it would be
enough.
Now it's clear in my mind and this replaces allowedTokens by simply
StringEscapeUtils::unescapeHtml4
So this also removes the recently added allowedTokens in
security.properties.
They are now useless.
Also it's quite better because it handles all cases known or unknown.
Better keep allowedTokens list as short as possible.
Conflicts handled by hand in both files
---
framework/security/config/security.properties | 2 +-
.../apache/ofbiz/webapp/control/ControlFilter.java | 41 ++++++----------------
2 files changed, 11 insertions(+), 32 deletions(-)
diff --git a/framework/security/config/security.properties
b/framework/security/config/security.properties
index 73bf5a910f..2658815a78 100644
--- a/framework/security/config/security.properties
+++ b/framework/security/config/security.properties
@@ -250,7 +250,7 @@
deniedWebShellTokens=java.,beans,freemarker,<script,javascript,<body,body ,<form
#-- SHA-1 versions of tokens containing (as String) at least one
deniedWebShellTokens
#-- This is notably used to allow special values in query parameters.
#-- If you add a token beware that it does not content ",". It's the separator.
-allowedTokens=$SHA$OFBiz$2naHrANKTniFcgLJk4oXr3IRQ48,$SHA$OFBiz$evAu1vcT5d1tjVXFTeVXU-6aNz8,$SHA$OFBiz$ORZaKvS7a0ee4gZb9P5hHuHnEyE,$SHA$OFBiz$T5DBu6tPuZzDCfYNci_23SrUa3Q,$SHA$OFBiz$BXhGVix7t3kfHrhNB0z9I0H9_rQ
+allowedTokens=$SHA$OFBiz$2naHrANKTniFcgLJk4oXr3IRQ48
allowStringConcatenationInUploadedFiles=false
diff --git
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlFilter.java
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlFilter.java
index 4b690d1a4e..badda5d9fc 100644
---
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlFilter.java
+++
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ControlFilter.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -37,7 +36,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.ofbiz.base.crypto.HashCrypt;
+import org.apache.commons.text.StringEscapeUtils;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.StringUtil;
import org.apache.ofbiz.base.util.UtilProperties;
@@ -118,6 +117,12 @@ public class ControlFilter implements Filter {
return
!GenericValue.getStackTraceAsString().contains("ControlFilterTests")
&& null == System.getProperty("SolrDispatchFilter");
}
+
+ private static List<String> getAllowedTokens() {
+ String allowedTokens = UtilProperties.getPropertyValue("security",
"allowedTokens");
+ return UtilValidate.isNotEmpty(allowedTokens) ?
StringUtil.split(allowedTokens, ",") : new ArrayList<>();
+ }
+
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
@@ -145,8 +150,7 @@ public class ControlFilter implements Filter {
if (httpRequest.getAttribute(FORWARDED_FROM_SERVLET) == null &&
!allowedPaths.isEmpty()) {
// check to make sure the requested url is allowed
// get the request URI without the webapp mount point
- String requestUri =
URLDecoder.decode(httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()),
"UTF-8");
-
+ String requestUri =
StringEscapeUtils.unescapeHtml4(URLDecoder.decode(httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()),
"UTF-8"));
// Reject wrong URLs
String queryString = null;
@@ -169,18 +173,13 @@ public class ControlFilter implements Filter {
}
if
(!requestUri.matches("/control/logout;jsessionid=[A-Z0-9]{32}\\.jvm1")) {
- boolean bypass = true;
- if (queryString != null) {
- List<String> queryStringList =
StringUtil.splitWithStringSeparator(queryString.toLowerCase(), "&");
- bypass = isAnyAllowedToken(queryStringList, ALLOWEDTOKENS);
- }
- if (requestUri != null && !bypass) { // "null" allows tests
with Mockito. ControlFilterTests sends null.
+ if (requestUri != null) { // "null" allows tests with Mockito
because ControlFilterTests sends null.
try {
String url = new URI(requestUri)
.normalize().toString()
.replaceAll(";", "")
.replaceAll("(?i)%2e", "");
- if (!((HttpServletRequest)
request).getRequestURL().toString().equals(url)) {
+ if (!requestUri.toString().equals(url)) {
Debug.logError("For security reason this URL is
not accepted", module);
throw new RuntimeException("For security reason
this URL is not accepted");
}
@@ -233,24 +232,4 @@ public class ControlFilter implements Filter {
public void destroy() {
}
-
- private static List<String> getAllowedTokens() {
- String allowedTokens = UtilProperties.getPropertyValue("security",
"allowedTokens");
- return UtilValidate.isNotEmpty(allowedTokens) ?
StringUtil.split(allowedTokens, ",") : new ArrayList<>();
- }
-
- // Check there is any allowedToken in URL
- private static boolean isAnyAllowedToken(List<String> queryParameters,
List<String> allowed) {
- boolean isOK = false;
- for (String parameter : queryParameters) {
- parameter = parameter.substring(0, parameter.indexOf("=") + 1);
- if (allowed.contains(HashCrypt.cryptBytes("SHA", "OFBiz",
parameter.getBytes(StandardCharsets.UTF_8)))) {
- isOK = true;
- break;
- } else {
- continue;
- }
- }
- return isOK;
- }
}