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 52bf8b30a1 Fixed: [SECURITY] (CVE-2024-36104) Path traversal leading 
to RCE (OFBIZ-13092)
52bf8b30a1 is described below

commit 52bf8b30a1ee8d78b457fe6b89cc79c7c56815ff
Author: Jacques Le Roux <jacques.le.r...@les7arts.com>
AuthorDate: Thu Jan 16 11:28:00 2025 +0100

    Fixed: [SECURITY] (CVE-2024-36104) Path traversal leading to RCE 
(OFBIZ-13092)
    
    I've got a strange issue that seems caused by one of this Jira modification:
    On demo environment, when clicking on several  sort field links, a
    'For security reason this URL is not accepted' error is thrown.
    
    For instance, if you perform a search on find party screen and try to sort 
by
    partyId, createdDate or else, you will get this message.
    
    I tried to reproduce it in a local trunk environment without success : the  
    uRIFiltered and the initialURI are the same.
    
    jleroux: but indeed when the same is done on a domain site, for instance
    official OFBiz demos, it's reproducible in all demo instances.
    
    This fixes it, with some more: refactoring, formatting and renaming
    
    Thanks: Leïla for report and details.
    
    Conflicts handled by hand (a lot) in ControlFilter.java
---
 framework/security/config/security.properties      |  2 +-
 .../org/apache/ofbiz/security/SecuredUpload.java   |  6 --
 .../apache/ofbiz/webapp/control/ControlFilter.java | 69 ++++++++++++++++++----
 3 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/framework/security/config/security.properties 
b/framework/security/config/security.properties
index 2658815a78..1204f9bd05 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
+allowedTokens=$SHA$OFBiz$2naHrANKTniFcgLJk4oXr3IRQ48,$SHA$OFBiz$evAu1vcT5d1tjVXFTeVXU-6aNz8,$SHA$OFBiz$-MaMN-Dui294v86UT1T8BkG3v8k
 
 allowStringConcatenationInUploadedFiles=false
 
diff --git 
a/framework/security/src/main/java/org/apache/ofbiz/security/SecuredUpload.java 
b/framework/security/src/main/java/org/apache/ofbiz/security/SecuredUpload.java
index 5d557ed80a..059ca043e7 100644
--- 
a/framework/security/src/main/java/org/apache/ofbiz/security/SecuredUpload.java
+++ 
b/framework/security/src/main/java/org/apache/ofbiz/security/SecuredUpload.java
@@ -846,12 +846,6 @@ public class SecuredUpload {
         return UtilValidate.isNotEmpty(deniedTokens) ? 
StringUtil.split(deniedTokens, ",") : new ArrayList<>();
     }
 
-    public static List<String> getallowedTokens() {
-        String allowedTokens = UtilProperties.getPropertyValue("security", 
"allowedTokens");
-        return UtilValidate.isNotEmpty(allowedTokens) ? 
StringUtil.split(allowedTokens, ",") : new ArrayList<>();
-    }
-
-
     private static boolean checkMaxLinesLength(String fileToCheck) {
         if (MAXLINELENGTH == 0) {
             return true;
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 9776e64e5d..19d0697806 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,10 @@ 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;
 import java.util.Set;
 
 import javax.servlet.Filter;
@@ -34,7 +37,10 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.ofbiz.base.crypto.HashCrypt;
 import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.StringUtil;
+import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.entity.GenericValue;
 import org.apache.ofbiz.security.SecuredUpload;
@@ -76,6 +82,7 @@ public class ControlFilter implements Filter {
     private String redirectPath;
     protected int errorCode;
     private Set<String> allowedPaths = new HashSet<>();
+    private static final List<String> ALLOWEDTOKENS = getAllowedTokens();
 
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
@@ -140,29 +147,45 @@ public class ControlFilter implements Filter {
             // get the request URI without the webapp mount point
             String requestUri = 
URLDecoder.decode(httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()),
 "UTF-8");
 
+
             // Reject wrong URLs
-            String queryString = httpRequest.getQueryString();
+            String queryString = null;
+            try {
+                queryString = new URI(requestUri).getQuery();
+
+            } catch (URISyntaxException e) {
+                Debug.logError("Weird URI: " + e, module);
+                throw new RuntimeException(e);
+            }
+
             if (queryString != null) {
                 queryString = URLDecoder.decode(queryString, "UTF-8");
                 if (UtilValidate.isUrl(queryString)
-                        || 
!SecuredUpload.isValidText(queryString.toLowerCase(), 
SecuredUpload.getallowedTokens(), true)
-                        && isSolrTest()) {
+                        || 
!SecuredUpload.isValidText(queryString.toLowerCase(), ALLOWEDTOKENS, true)
+                            && isSolrTest()) {
                     Debug.logError("For security reason this URL is not 
accepted", module);
                     throw new RuntimeException("For security reason this URL 
is not accepted");
                 }
             }
+
             if 
(!requestUri.matches("/control/logout;jsessionid=[A-Z0-9]{32}\\.jvm1")) {
-                try {
-                    String url = new URI(((HttpServletRequest) 
request).getRequestURL().toString())
-                            .normalize().toString()
-                            .replaceAll(";", "")
-                            .replaceAll("(?i)%2e", "");
-                    if (!((HttpServletRequest) 
request).getRequestURL().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");
+                boolean bypass = true;
+                if (queryString != null) {
+                    bypass = 
isAnyAllowedToken(StringUtil.split(queryString.toLowerCase(), "Y&amp;"), 
ALLOWEDTOKENS);
+                }
+                if (requestUri != null && !bypass) { // "null" allows tests 
with Mockito. ControlFilterTests sends null.
+                    try {
+                        String url = new URI(((HttpServletRequest) 
request).getRequestURL().toString())
+                                .normalize().toString()
+                                .replaceAll(";", "")
+                                .replaceAll("(?i)%2e", "");
+                        if (!((HttpServletRequest) 
request).getRequestURL().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");
+                        }
+                    } catch (URISyntaxException e) {
+                        throw new RuntimeException(e);
                     }
-                } catch (URISyntaxException e) {
-                    throw new RuntimeException(e);
                 }
             }
 
@@ -209,4 +232,24 @@ 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;
+    }
 }

Reply via email to