5

In the following C# example I'm querying AD's configuration container for Exchange overrides. If the domain name in unsanitised the end user could get LDAP to read a different object then intended.

I'm not sure if other actions other than read are possible.

    static string GetExchangeDomain(string targetDomain)
    {
        string retFoundDomain = "";

        string remoteDomainLocation = "CN=Microsoft Exchange,CN=Services,";
        string filter = string.Format("(domainName={0})", targetDomain);

        string[] props = new string[] { "targetAddress", "description" };

        using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE"))
        {
            string serverName = rootDSE.Properties["dnsHostName"].Value as string;
            string domainContext = rootDSE.Properties["configurationNamingContext"].Value as string;

            using (DirectoryEntry exchOrgDE = new DirectoryEntry("LDAP://" + serverName + "/" + remoteDomainLocation + domainContext))
            {
                foreach (DirectoryEntry item in exchOrgDE.Children)
                {
                    string orgName = item.Name;

                    if (item.Properties["objectCategory"][0].ToString().StartsWith("CN=ms-Exch-Organization-Container"))
                    {
                        using (DirectoryEntry exchangeRemoteDomains = new DirectoryEntry("LDAP://" + serverName + "/CN=Internet Message Formats,CN=Global Settings," + orgName + "," + remoteDomainLocation + domainContext))
                        {
                            using (DirectorySearcher searcher = new DirectorySearcher(exchangeRemoteDomains, filter, new string[] { "cn", "domainName" }))
                            {
                                searcher.ReferralChasing = ReferralChasingOption.All;
                                SearchResult result = searcher.FindOne();

                                if (result != null)
                                {
                                    retFoundDomain = result.Properties["cn"][0].ToString().TrimEnd(("." + targetDomain).ToCharArray());
                                }
                            }
                        }
                    }
                    item.Dispose(); // not sure if this is required...
                }
            }
        }

        return retFoundDomain;
    }

Question

  • Are there any examples or tools that test for LDAP injection?

  • What is the correct way to sanitize the input for an LDAP query?

makerofthings7
  • 50,090
  • 54
  • 250
  • 536

2 Answers2

4

In worst case an attacker can run query of his choice in LDAP directory. Results may differ but definitely you don't want attacker to do this.

If you are using .NET framework, you could use AntiXSS library. I know that LDAP injection is not XSS, nevertheless XSS is also a form of injection and correct way to prevent this kind of vulnerabilities is to validate input date and encode it correctly before passing it to an interpreter (browser, SQL server, LDAP server). AntiXSS library offers functions intended to encode potentially dangerous data before passing it to LDAP (LdapDistinguishedNameEncode, LdapFilterEncode). You can also take a look into OWASP ESAPI project, especially into DefaultEncoder.encodeForLDAP function.

pgolen
  • 529
  • 2
  • 5
2

Here is a little more detail.

ESAPI for Java has two encoding functions for LDAP injection protection. http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encoder.html

    /**
     * Encode data for use in LDAP queries.
     *
     * @param input the text to encode for LDAP
     *
     * @return input encoded for use in LDAP
     */
    String encodeForLDAP(String input);

    /**
     * Encode data for use in an LDAP distinguished name.
     *
     *  @param input the text to encode for an LDAP distinguished name
     *
     *  @return input encoded for use in an LDAP distinguished name
     */
    String encodeForDN(String input);

.NET AntiXSS (now the Encoder class) have similar functions with better explanations. These include Encoder.LdapFilterEncode(string), Encoder.LdapDistinguishedNameEncode(string) and Encoder.LdapDistinguishedNameEncode(string, bool, bool). Link

Encoder.LdapFilterEncode encodes input according to RFC4515 where unsafe values are converted to \XX where XX is the representation of the unsafe character.

Encoder.LdapDistinguishedNameEncode encodes input according to RFC 2253 where unsafe characters are converted to #XX where XX is the representation of the unsafe character and the comma, plus, quote, slash, less than and great than signs are escaped using slash notation (\X). In addition to this a space or octothorpe (#) at the beginning of the input string is \ escaped as is a space at the end of a string.

LdapDistinguishedNameEncode(string, bool, bool) is also provided so you may turn off the initial or final character escaping rules, for example if you are concatenating the escaped distinguished name fragment into the midst of a complete distinguished name.

Glorfindel
  • 2,235
  • 6
  • 18
  • 30
Manicode
  • 121
  • 1