My blog, keeping you up-to-date with my latest news.

 

Escaping special chars within LDAP

PHP • 2013-08-06

 

Problem?

When programming against any LDAP backend it’s good to sanitize any user input that may go into a search filter.
A typical case is authentication applications, where an input username or email must be used to resolve a user’s distinct name (DN) in the LDAP directory.

You shouldn’t have to worry about anything on this issue if you’re using Zend Framework 2 properly. The Zend\Ldap\Filter\AbstractFilter class embeds escapeValue() method, which is used specifically for escaping values used in LDAP queries

Quick attack

Consider as an example the following search filter template, which is used to get a user based on finding an exact match of their mail attribute.

(&(mail=%s)(objectClass=People))

The %s placeholder is replaced by the user input and the resulting string is used to create the LDAP search filter.
If the user enters test@pierrerambaud.com into the login form the resulting search filter string would become this:

(&(mail=test@pierrerambaud.com)(objectClass=People))

However, if the user enters *, this will trigger a match-any search, since this is what the asterisk means in the context of LDAP search filters.

(&(mail=*)(objectClass=People))

in combination with unescaped value merged in place of login It will be fairly easy for an attacker to log into your application by providing value for username like

*)(userPassword=123456

Again, it’s an obvious flaw and if you let unescaped values into queries, providing such a clear opportunity to inject additional filter rules to the query is a really big mistake.

The previous query with the injection should look like:

(&(mail=*)(userPassword=123456)(objectClass=People))

It’s a completely legitimate query which would return all of the users who have password of ‘123456‘.
And as we all know, it’s the second most used password on the internet.

Solution

To prevent this from happening you may limit the range of acceptable input characters or you may use a function that sanitises the input by escaping all special characters in the assertion value.
The special search filter characters and how to escape them is fully described in RFC 4515 (String Representation of LDAP).

function ldapEscape($string, $dn = null) 
{
    $escapeDn = array('\\', '*', '(', ')', "\x00");
    $escape   = array('\\', ',', '=', '+', '<', '>', ';', '"', '#');

    $search = array();
    if ($dn === null) {
        $search = array_merge($search, $escapeDn, $escape);
    } elseif ($dn === false) {
        $search = array_merge($search, $escape);
    } else {
        $search = array_merge($search, $escapeDn);
    }

    $replace = array();
    foreach ($search as $char) {
        $replace[] = sprintf('\\%02x', ord($char));
    }

    return str_replace($search, $replace, $string);
}

$user = '*)(username=test+1234@gpierrerambaud.com)';
var_dump("cn=" . ldapEscape($user));
//string(64) "cn=\5c2a\5c29\5c28username\3dtest\2b1234@gpierrerambaud.com\5c29"
var_dump("cn=" . ldapEscape($user, true));
//string(52) "cn=\2a\29\28username=test+1234@gpierrerambaud.com\29"
var_dump("cn=" . ldapEscape($user, false));
//string(48) "cn=*)(username\3dtest\>2b1234@gpierrerambaud.com)"

Code and tests are available on my Github account: https://github.com/PierreRambaud/blog/tree/master/escaping-special-chars-within-ldap

<< Back to Blog Discuss this post

 

Comments

 

No comments

 

Add a comment

 

Categories