You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 26 Next »

The Lightweight Directory Access Protocol (LDAP) allows an application to remotely perform operations such as searching and modifying records existing in directories. LDAP injection results from inadequate input sanitization and validation and allows malicious users to glean restricted information using the directory service.

A white-list can be used to restrict input to a list of valid characters. Characters that must be excluded from white-lists — including JNDI meta-characters and LDAP special characters — are:

Character

Name

' and "

Single and double quote

/ and \

Forward-slash and back-slash

\ \

Double slashes*

space

Space character at beginning or end of string

#

Hash character at the beginning of the string

< and >

Angle brackets

, and ;

Comma and semi-colon

+ and *

Addition and multiplication operators

( and )

Round braces

\u0000

Unicode NULL character

* This is a character sequence

LDAP Injection Example

Consider an LDAP Data Interchange Format (LDIF) file that contains records in the following format:

dn: dc=example,dc=com
objectclass: dcobject
objectClass: organization
o: Some Name
dc: example

dn: ou=People,dc=example,dc=com
ou: People
objectClass: dcobject
objectClass: organizationalUnit
dc: example

dn: cn=Manager,ou=People,dc=example,dc=com
cn: Manager
sn: John Watson
# Several objectClass definitions here (omitted)
userPassword: secret1
mail: john@holmesassociates.com

dn: cn=Senior Manager,ou=People,dc=example,dc=com
cn: Senior Manager
sn: Sherlock Holmes
# Several objectClass definitions here (omitted)
userPassword: secret2
mail: sherlock@holmesassociates.com

A search for a valid username and password often takes the form:

(&(sn=<USERSN>)(userPassword=<USERPASSWORD>))

However, an attacker could bypass authentication by using S* for the USERSN field and * for the USERPASSWORD field. Such input would yield every record whose USERSN field began with S.

An authentication routine that permitted LDAP injection would allow unauthorized users to log in. Likewise, a search routine would allow an attacker to discover part or all of the data in the directory.

Noncompliant Code Example

This noncompliant code example allows a caller of the method searchRecord() to search for a record in the directory using the LDAP protocol. The string filter is used to filter the result set for those entries that match a user name and password supplied by the caller. When a malicious user enters specially crafted input, as outlined above, this elementary authentication scheme fails to confine the output of the search query to the information for which the user has access privileges.

// String userSN = "S*"; // Invalid
// String userPassword = "*"; // Invalid
public class LDAPInjection {        
  private void searchRecord(String userSN, String userPassword) throws NamingException {        
    Hashtable<String, String>  env = new Hashtable<String, String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    try {
      DirContext dctx = new InitialDirContext(env);
		    
      SearchControls sc = new SearchControls();
      String[] attributeFilter = {"cn", "mail"};
      sc.setReturningAttributes(attributeFilter);
      sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
      String base = "dc=example,dc=com";

      // The following resolves to (&(sn=S*)(userPassword=*))      
      String filter = "(&(sn=" + userSN + ")(userPassword=" + userPassword + "))"; 

      NamingEnumeration<?> results = dctx.search(base, filter, sc);
      while (results.hasMore()) {
        SearchResult sr = (SearchResult) results.next();
        Attributes attrs = sr.getAttributes();
        Attribute attr = attrs.get("cn");
        System.out.println(attr.get());
        attr = attrs.get("mail");
        System.out.println(attr.get());
      }
      dctx.close();
    } catch (NamingException e) {
      // Handle
    }
  }
}

Compliant Solution

This compliant solution uses a white-list to sanitize user input so that the filter string contains only valid characters. In this code, userSN may contain only letters and spaces whereas a password may contain only alphanumeric characters.

// String userSN = "Sherlock Holmes"; // Valid
// String userPassword = "secret2";   // Valid

sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String base = "dc=example,dc=com";
           
if(!userSN.matches("[\\w\\s]*") || !userPassword.matches("[\\w]*")) {
  throw new IllegalArgumentException("Invalid input");
} 
            	
String filter = "(&(sn = " + userSN + ")(userPassword=" + userPassword + "))";      

When a database field such as a password must include special characters, it is critical to ensure that the authentic data is stored in sanitized form in the database and also that any user input is normalized before the validation or comparison takes place. We discourage use of characters that have special meanings in JNDI and LDAP in the absence of a comprehensive normalization and white-listing based routine. Refer to the guideline VOID IDS04-J. Properly encode or escape output for examples on output encoding and escaping. Special characters must be transformed to sanitized safe values before they are added to the white-list expression against which input will be validated. Likewise, normalization of user input (escaping and encoding) should occur before the validation step.

Risk Assessment

Failure to sanitize untrusted input can result in information disclosure and privilege escalation.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

IDS11-J

high

likely

medium

P18

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this guideline on the CERT website.

Bibliography

[[API 2006]]
[[OWASP 2008]] Preventing LDAP Injection in Java


IDS10-J. Prevent XML external entity attacks      13. Input Validation and Data Sanitization (IDS)      IDS12-J. Prevent code injection

  • No labels