CVE-2021-32651 (published 2021-06-01T18:15Z)

OneDev is a development operations platform. If the LDAP external authentication mechanism is enabled in OneDev versions 4.4.1 and prior, an attacker can manipulate a user search filter to send forged queries to the application and explore the LDAP tree using Blind LDAP Injection techniques. The specific payload depends on how the User Search Filter property is configured in OneDev. This issue was fixed in version 4.4.2.

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

Weakness information:
cwe_id: CWE-90
cwe_name: Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection')
description: The product constructs all or part of an LDAP query using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended LDAP query when it is sent to a downstream component.
extended_description: 
            
         
         

Fix information:
repo_url: https://github.com/theonedev/onedev
commit_details: repo_url: https://github.com/theonedev/onedev
author: Robin Shen
author_date: 2021-05-29 10:41:52+08:00
msg: Fix issue #304 - Potential information leak via Ldap injection when ldap
authenticator is enabled
repository: repo_url: https://github.com/theonedev/onedev
repo_name: theonedev/onedev
description: Git Server with CI/CD, Kanban, and Packages. Seamless integration. Unparalleled experience.
repo_language: Java
owner: theonedev
file_changes: filename: LdapAuthenticator.java
change_type: ModificationType.MODIFY
diff: @@ -181,7 +181,9 @@ public class LdapAuthenticator extends Authenticator {
 		} catch (InvalidNameException e) {
 			throw new RuntimeException(e);
 		}
-        String userSearchFilter = StringUtils.replace(getUserSearchFilter(), "{0}", token.getUsername());
+		
+        String userSearchFilter = StringUtils.replace(getUserSearchFilter(), "{0}", 
+        		escape(token.getUsername()));
         userSearchFilter = StringUtils.replace(userSearchFilter, "\\", "\\\\");
         logger.debug("Evaluated user search filter: " + userSearchFilter);
         
@@ -437,4 +439,46 @@ public class LdapAuthenticator extends Authenticator {
 		return getUserSshKeyAttribute() != null;
 	}
 	
+	/* Copied from Spring LdapEncoder.java */
+    private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1];
+
+    static {
+
+        // Filter encoding table -------------------------------------
+
+        // fill with char itself
+        for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++) {
+            FILTER_ESCAPE_TABLE[c] = String.valueOf(c);
+        }
+
+        // escapes (RFC2254)
+        FILTER_ESCAPE_TABLE['*'] = "\\2a";
+        FILTER_ESCAPE_TABLE['('] = "\\28";
+        FILTER_ESCAPE_TABLE[')'] = "\\29";
+        FILTER_ESCAPE_TABLE['\\'] = "\\5c";
+        FILTER_ESCAPE_TABLE[0] = "\\00";
+
+    }
+
+    private static String escape(String value) {
+        // make buffer roomy
+        StringBuilder encodedValue = new StringBuilder(value.length() * 2);
+
+        int length = value.length();
+
+        for (int i = 0; i < length; i++) {
+
+            char c = value.charAt(i);
+
+            if (c < FILTER_ESCAPE_TABLE.length) {
+                encodedValue.append(FILTER_ESCAPE_TABLE[c]);
+            } else {
+                // default: add the char
+                encodedValue.append(c);
+            }
+        }
+
+        return encodedValue.toString();
+    }	
+	
 }

programming_language: Java