What is LDAP Injection? Types, Examples and How to Prevent It
Table of Contents
What is LDAP (Lightweight Directory Access Protocol)?
A lighter-weight version of the Directory Access Protocol (DAP), Lightweight Directory Access Protocol (LDAP) is an open, vendor-neutral, industry-standard application protocol for accessing and maintaining distributed directory information services over an Internet Protocol (IP) network. LDAP is widely applied in web development because of the centralized authentication, enabling users to log into different websites and applications with a single identity.
The unified directory service supported by LDAP facilitates the sharing of user and resource directories among various applications and services. In security and authentication management, LDAP’s support of data encryption and security authentication mechanisms has made it an ideal choice for managing user data, implementing authorization with SSL, and simplifying resource access in large organizations and enterprise environments.
LDAP data structure
LDAP stores data in a hierarchical directory tree where each entry is a unique node. Each node consists of one or more attributes that define its characteristics. For example, a user node may contain details like UID, username, password, email, etc.
LDAP is ideal for storing data like organizational structure, user information and permission settings in a tree-like format. It features a lightweight design, optimizes read operations, and is more applicable in scenarios where there are far more read operations than write operations.
Specialized libraries are required to interact with the LDAP server. In Java, JNDI (Java Naming and Directory Interface) is usually used for LDAP operations. Here is a simple query code example.
public class LdapConnection {
public DirContext search(String url, String username, String password) throws Exception {
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx = new InitialDirContext(env);
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult> results = ctx.search(searchBase, searchFilter, searchControls);
while (results.hasMore()) {
SearchResult result = results.next();
System.out.println("Name: " + result.getName());
}
}
LDAP injection attacks
Despite its several advantages, LDAP has also become a hot target for malicious attacks due to its widespread application. With the purpose of destroying the app or making illegal profits, hackers launch malicious LDAP injection attacks on systems that fail to handle users’ data properly. Let’s learn more about LDAP attack modes below:
Attack modes
Basic attack and blind attack are the two ways that LDAP Injection is performed.
Basic Attack
A basic attack is simple, clear, and direct: attackers locate the vulnerability and steal data by tampering with query operations with malicious input. For instance, it is most vulnerable if you directly create query conditions with string concatenation, such as:
String userFilter = "(cn=" + userInput + ")";
Blind Attack
In the blind attack mode, the attacker constantly attempts to interact with the LDAP server and infer based on the information returned by the server until a usable malicious query statement is found. This attack mode is chosen when there is not enough information, and the attacker searches for vulnerabilities through constant attempts. In the following example, where the user’s permissions are obtained via UID, the attacker infers whether the information returned by the method can be used or not.
public String getUserRole(String uid) {
String query = "(uid=" + uid + ")";
// LDAP query & return roleInfo
}
Meanwhile, attackers try to obtain more precise or more user information by passing in different searchCriteria.
public List<String> searchUser(String searchCriteria) {
String query = "(&(objectClass=person)(|" + searchCriteria + "))";
// LDAP query & return user list
}
Both the above two ways enable the attacker to obtain permissions and further imperil the LDAP system such as adding, deleting and modifying information.
The userInput in the code below is not verified, and the attacker can add any user information they want once they obtain the addUser permission.
public void addUser(String userInput) {
String dn = "uid=" + userInput + ",dc=example,dc=com";
Attributes attributes = new BasicAttributes();
Attribute attribute = new BasicAttribute("objectClass", "inetOrgPerson");
attributes.put(attribute);
// LDAP add op
context.createSubcontext(dn, attributes);
}
Similarly, the same issue lies in the deleteUser and modifyUser below.
public void deleteUser(String userInput) {
String dn = "uid=" + userInput + ",dc=example,dc=com";
// LDAP delete op
context.destroySubcontext(dn);
}
public void updateUser(String username, String userAttribute, String newValue) {
String dn = "uid=" + username + ",dc=example,dc=com";
ModificationItem[] mods = new ModificationItem[1];
Attribute mod = new BasicAttribute(userAttribute, newValue);
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, mod);
context.modifyAttributes(dn, mods);
}
AND and OR in Attacks
Attackers often use the AND operator to narrow the querying scope. Only the records that meet all criteria are returned.
(&(cond1)(cond2)(cond3))
For example, the following query narrows the query scope to user information.
String filter = "(&(objectClass=user)(uid=" + uid + "))";
On the contrary, the OR operator broadens the query scope and returns records that meet either condition, ensuring that at least one of the listed conditions is met.
(|(cond1)(cond2)(cond3))
For example, the following search returns results once either user or email is matched.
String filter = "(|(uid=" + userInput + ")(mail=" + emailInput + "))";
The attackers’ flexible use of AND and OR operators is greatly challenging to the system security.
Related: Preventing SQL Injections With Python
LDAP attack types
Common LDAP attacks can be classified into Information Disclosure, Authentication Bypass and Denial of Service(DoS). Let’s delve into these types of attacks in detail:
Information disclosure
Information Disclosure occurs when user input is used to build an LDAP query before it is properly processed. Via LDAP vulnerability, attackers access and disclose sensitive information that should not be made public, such as user credentials, personal data, passwords, etc., and use them for further crimes like identity and credit fraud.
Authentication bypass
An authentication bypass typically occurs when an application fails to validate an LDAP query input properly. The attacker constructs a malicious LDAP query statement and changes the authentication logic of the application to bypass the authentication mechanism.
For example, an attacker could inject special query parameters so that an LDAP query always returns a positive result regardless of the actual username and password combination. In this way, an attacker can log in as any user and access protected resources and data.
The attackers’ full access to the system without security controls and audit mechanisms can cause large-scale data leaks and illegal data modifications, jeopardizing the security of the entire system.
Denial of Service (DoS)
Denial of Service (DoS) avails itself of the resource limitations of the LDAP server and consumes server resources by sending a large number of complex or specially constructed requests or creating multiple concurrent connections to fail the normal service. It attacks mainly by exhausting the target system’s resources, such as memory, CPU and network bandwidth.
The interruption of the core LDAP service affects the operations of all the systems that rely on it. For example, the Google incident in December 2020 was a typical LDAP system failure, which led to the service interruptions of YouTube and Gmail.
LDAP injection prevention cheat sheet
Remediation is reactive, and prevention is proactive. You can take better control of your security with this essential cheat sheet of defense mechanisms for preventing LDAP Injection attacks:
- Use Parameterized Queries: Prevent LDAP injection by avoiding direct string concatenation, such as:
String searchFilter = "(&(uid={0})(userPassword={1}))";
ctx.search("dc=example,dc=com", searchFilter, new Object[]{username, password}, searchControls);
- Input Validation: Validate all user inputs for format and legitimacy. Use regex to check if the input matches the expected format.
if (!username.matches("[A-Za-z0-9]{1,30}")) {
throw new IllegalArgumentException("Invalid input");
}
- Escape Special Characters: Escaping special characters in LDAP search input values ensures they are treated as literal characters rather than control characters in queries.
String sanitizedInput = input.replace("(", "\\28").replace(")", "\\29");
- Implement Access Controls: Restrict LDAP access based on the principle of least privilege.
- Encrypt LDAP Communications: Use SSL/TLS for LDAP communications to ensure data privacy.
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.SECURITY_PROTOCOL, "ssl");
DirContext ctx = new InitialDirContext(env);
- Audit and Monitor LDAP Access: Regularly audit and monitor LDAP access logs for suspicious activities.
- Improve Authentication Method: Use strong authentication mechanisms, such as multi-factor authentication.
- Sanitize Logs: Sanitize data before logging in order to avoid information leakage.
log.info("User accessed: " + sanitizeForLog(username));
- Manage Session: Implement secure session management for LDAP interactions, for instance, using tokens and timeout policies.
- Limit LDAP Query: Limit the scope and complexity of LDAP queries, such as by setting query size and time limits in the LDAP search controls.
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setCountLimit(100);
controls.setTimeLimit(3000);
- Harden LDAP Schema: Improve the LDAP schema to prevent unauthorized modifications, for example, restrict schema modification rights to admin users only.
- Disable Unused LDAP Services: Turn off unused LDAP functionalities to reduce the attack surface.
- Secure LDAP Server: Install LDAP-specific firewalls to filter malicious traffic.
- Use Secure LDAP Libraries: Utilize well-known, secure LDAP libraries in your applications, for instance, UnboundID for Java.
- Update LDAP Software: Keep LDAP servers and clients updated with the latest security patches.
- Backup and Recovery: Have a robust backup and recovery plan for LDAP data.
- Conduct Regular Audits: Conduct security audits of the LDAP infrastructure regularly, including schema validation, auditing logs, etc.
Conclusion
LDAP, while offering undeniable benefits, can be susceptible to malicious attacks. To safeguard your organization, prioritizing proactive prevention strategies like parameterized queries, input validation, and strong authentication mechanisms is crucial. By employing the comprehensive defense mechanisms outlined in this article, you can significantly bolster your LDAP security posture, thwarting information disclosure, authentication bypasses, and Denial-of-Service attacks, thereby maintaining the integrity and availability of vital data.
Remember, vigilance is key – regularly update your software, conduct security audits, and foster a culture of cyber awareness to stay ahead of evolving threats and uphold a robust security posture. By proactively investing in securing your LDAP infrastructure, you can ensure the continued success and resilience of your business in today’s dynamic and ever-evolving threat landscape.