Skip to main content

LDAP injection

Need

Prevention of LDAP injection attacks

Context

  • Usage of Ruby for building dynamic and object-oriented applications
  • Usage of net-ldap for LDAP (Lightweight Directory Access Protocol) operations

Description

Non compliant code

def search_ldap(query)
conn = Net::LDAP.new( :host => ldap_host, :port => ldap_port, :auth => { :method => :simple, :username => ldap_username, :password => ldap_password })
filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")
treebase = "dc=example,dc=com"
conn.search(:base => treebase, :filter => filter)
end

In the above code, the search_ldap method constructs an LDAP filter using untrusted data (the query parameter). The filter is constructed by interpolating the query directly into the filter string. If an attacker can control the query parameter, they can potentially modify the LDAP filter in unexpected ways, leading to an LDAP Injection vulnerability.

For example, an attacker could provide a query value of *))(|(cn=*, which would modify the filter to return all objects in the directory, regardless of their cn attribute. This could lead to unauthorized disclosure of information or manipulation of the LDAP directory.

The vulnerability lies in the line:

filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")

Here, the query parameter is directly embedded into the LDAP filter without any sanitization or encoding, allowing potential LDAP Injection attacks.

Steps

  • Validate and sanitize user input before using it in LDAP queries.
  • Use parameterized queries or prepared statements to build LDAP queries.
  • Avoid concatenating user input directly into the LDAP query string.
  • Implement proper input validation to ensure that only expected characters are allowed.
  • Implement proper input encoding to prevent special characters from being interpreted as LDAP query syntax.
  • Use LDAP query libraries or frameworks that provide built-in protection against LDAP injection.
  • Regularly update and patch the LDAP server to mitigate any known vulnerabilities.
  • Implement strong authentication and authorization mechanisms to restrict access to the LDAP server.
  • Monitor and log LDAP queries for suspicious or malicious activities.
  • Educate developers about the risks of LDAP injection and provide secure coding guidelines.

Compliant code

def search_ldap(query)
conn = Net::LDAP.new( :host => ldap_host, :port => ldap_port, :auth => { :method => :simple, :username => ldap_username, :password => ldap_password })
query = Net::LDAP::Filter.escape(query)
filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")
treebase = "dc=example,dc=com"
conn.search(:base => treebase, :filter => filter)
end

The updated code now includes a call to Net::LDAP::Filter.escape(query). This method call is used to sanitize the user input query before it is used in the LDAP query. The Net::LDAP::Filter.escape method escapes any special characters in the input string that could be used to manipulate the LDAP query.

This is a critical step in preventing LDAP injection attacks, as it ensures that user input cannot modify the structure of the LDAP query. By escaping special characters, we ensure that they are treated as literal characters in the query string, rather than being interpreted as LDAP query syntax.

This is a simple and effective way to prevent LDAP injection attacks, but it should be used in conjunction with other security measures, such as input validation, using parameterized queries or prepared statements, and implementing strong authentication and authorization mechanisms. Regularly updating and patching the LDAP server, monitoring and logging LDAP queries, and educating developers about secure coding practices are also important steps in maintaining a secure system.

References