CVE-2021-25958 (published 2021-08-30T14:15Z)

In Apache Ofbiz, versions v17.12.01 to v17.12.07 implement a try catch exception to handle errors at multiple locations but leaks out sensitive table info which may aid the attacker for further recon. A user can register with a very long password, but when he tries to login with it an exception occurs.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-209
cwe_name: Generation of Error Message Containing Sensitive Information
description: The product generates an error message that includes sensitive information about its environment, users, or associated data.
extended_description: The sensitive information may be valuable information on its own (such as a password), or it may be useful for launching other, more serious attacks. The error message may be created in different ways:
           
             self-generated: the source code explicitly constructs the error message and delivers it
	     externally-generated: the external environment, such as a language interpreter, handles the error and constructs its own message, whose contents are not under direct control by the programmer
	   
	 An attacker may use the contents of error messages to help launch another, more focused attack. For example, an attempt to exploit a path traversal weakness (CWE-22) might yield the full pathname of the installed application. In turn, this could be used to select the proper number of ".." sequences to navigate to the targeted file. An attack using SQL injection (CWE-89) might not initially succeed, but an error message could reveal the malformed query, which would expose query logic and possibly even passwords or other sensitive information used within the query.
         

Fix information:
repo_url: https://github.com/apache/ofbiz-framework
commit_details: repo_url: https://github.com/apache/ofbiz-framework
author: Nicolas Malin
author_date: 2021-07-28 14:42:09+02:00
msg: Fixed: UserLoginHistory failed the store operation with large password (OFBIZ-12287)

Backport 2aa68dc4de8892e8a7cbb38c10a3a3dd65d233e5 from trunk

When you have a user with long password (greater than 256 characters) present in OFBiz and you try to log with, OFBiz return a long error message with sensitive information due to exceeding value size to store on the field UserLoginHistory.passwordUsed.

To solve this we don't return any information on the genericValue that failed and analyze the field passwordUsed to escape the case where the password set to login is create than the database field capacity.

Thanks to Daniel Elkabes <daniel.elkabes@whitesourcesoftware.com> and Hagai Wechsler <hagai.wechsler@whitesourcesoftware.com> from white source software to raise the problem.
repository: repo_url: https://github.com/apache/ofbiz-framework
repo_name: apache/ofbiz-framework
description: Apache OFBiz is an open source product for the automation of enterprise processes. It includes framework components and business applications for ERP, CRM, E-Business/E-Commerce, Supply Chain Management and Manufacturing Resource Planning. OFBiz provides a foundation and starting point for reliable, secure and scalable enterprise solutions.
repo_language: Java
owner: apache
file_changes: filename: LoginServices.java
change_type: ModificationType.MODIFY
diff: @@ -47,6 +47,7 @@ import org.apache.ofbiz.entity.condition.EntityCondition;
 import org.apache.ofbiz.entity.condition.EntityFunction;
 import org.apache.ofbiz.entity.condition.EntityOperator;
 import org.apache.ofbiz.entity.model.ModelEntity;
+import org.apache.ofbiz.entity.model.ModelField;
 import org.apache.ofbiz.entity.transaction.GenericTransactionException;
 import org.apache.ofbiz.entity.transaction.TransactionUtil;
 import org.apache.ofbiz.entity.util.EntityListIterator;
@@ -334,8 +335,12 @@ public class LoginServices {
                                         }
 
                                         // ONLY save the password if it was incorrect
-                                        if ("N".equals(successfulLogin) && !"false".equals(EntityUtilProperties.getPropertyValue("security", "store.login.history.incorrect.password", delegator))) {
-                                            ulhCreateMap.put("passwordUsed", password);
+                                        // we will check in the hash size isn't too huge for the store other wise store a fix string
+                                        if ("N".equals(successfulLogin) && !"false".equals(EntityUtilProperties.getPropertyValue("security",
+                                                "store.login.history.incorrect.password", delegator))) {
+                                            ulhCreateMap.put("passwordUsed", isGivenPasswordCanBeStored(delegator, password)
+                                                    ? " TOO LONG FOR STORAGE "
+                                                    : password);
                                         }
 
                                         delegator.create("UserLoginHistory", ulhCreateMap);
@@ -346,7 +351,6 @@ public class LoginServices {
                                 if (doStore) {
                                     geeErrMsg += " and updating login status to reset hasLoggedOut, unsuccessful login count, etc.";
                                 }
-                                geeErrMsg += ": " + e.toString();
                                 try {
                                     TransactionUtil.rollback(beganTransaction, geeErrMsg, e);
                                 } catch (GenericTransactionException e2) {
@@ -435,6 +439,30 @@ public class LoginServices {
         return result;
     }
 
+    /**
+     * To escape an exception when the password store due to limitation size for passwordUsed field, we analyse if it's possible.
+     * @param delegator
+     * @param password
+     * @return
+     * @throws GenericEntityException
+     */
+    private static boolean isGivenPasswordCanBeStored(Delegator delegator, String password)
+            throws GenericEntityException {
+        ModelEntity modelEntityUserLoginHistory = delegator.getModelEntity("UserLoginHistory");
+        ModelField passwordUsedField = modelEntityUserLoginHistory.getField("passwordUsed");
+        int maxPasswordSize = delegator.getEntityFieldType(
+                modelEntityUserLoginHistory,
+                passwordUsedField.getType()).stringLength();
+        int passwordUsedCurrentSize = password.length();
+
+        // if the field is encrypted, we check the size of the hashed result
+        ModelField.EncryptMethod encryptMethod = passwordUsedField.getEncryptMethod();
+        if (encryptMethod.isEncrypted()) {
+            passwordUsedCurrentSize = delegator.encryptFieldValue("UserLoginHistory", encryptMethod, password).toString().length();
+        }
+        return passwordUsedCurrentSize > maxPasswordSize;
+    }
+
     public static void createUserLoginPasswordHistory(GenericValue userLogin) throws GenericEntityException{
         int passwordChangeHistoryLimit = 0;
         Delegator delegator = userLogin.getDelegator();

programming_language: Java