CVE-2020-35518 (C, published 2021-03-26T17:15Z)
Description: value: When binding against a DN during authentication, the reply from 389-ds-base will be different whether the DN exists or not. This can be used by an unauthenticated attacker to check the existence of an entry in the LDAP database.
Severity: MEDIUM (CVSS v3 base score: 5.3)
Weakness: CWE-203 \u2014 Observable Discrepancy
The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not.
Repository: https://github.com/389ds/389-ds-base
Files changed:
dirsrvtests/tests/suites/basic/basic_test.py
ldap/servers/slapd/back-ldbm/ldbm_bind.c
ldap/servers/slapd/dse.c
Commit message: Issue 4609 - CVE - info disclosure when authenticating

Description:  If you bind as a user that does not exist.  Error 49 is returned
              instead of error 32.  As error 32 discloses that the entry does
              not exist.  When you bind as an entry that does not have userpassword
              set then error 48 (inappropriate auth) is returned, but this
              discloses that the entry does indeed exist.  Instead we should
              always return error 49, even if the password is not set in the
              entry.  This way we do not disclose to an attacker if the Bind
              DN exists or not.

Relates: https://github.com/389ds/389-ds-base/issues/4609

Reviewed by: tbordaz(Thanks!)


Vulnerable code:
from lib389.idm.user import UserAccounts



    1: bind as non existing entry
    2: check that bind info does not report 'No such entry'

    1: pass
    2: pass
            slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                                   NULL, 0, NULL);
        slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL);
            slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);

Fixed code:
from lib389.idm.user import UserAccount, UserAccounts
        1: bind as non existing entry
        2: check that bind info does not report 'No such entry'
        1: pass
        2: pass
def test_bind_entry_missing_passwd(topology_st):
    """
    :id: af209149-8fb8-48cb-93ea-3e82dd7119d2
    :setup: Standalone Instance
    :steps:
        1. Bind as database entry that does not have userpassword set
        2. Bind as database entry that does not exist
        1. Bind as cn=config entry that does not have userpassword set
        2. Bind as cn=config entry that does not exist
    :expectedresults:
        1. Fails with error 49
        2. Fails with error 49
        3. Fails with error 49
        4. Fails with error 49
    """
    user = UserAccount(topology_st.standalone, DEFAULT_SUFFIX)
    with pytest.raises(ldap.INVALID_CREDENTIALS):
        # Bind as the suffix root entry which does not have a userpassword
        user.bind("some_password")

    user = UserAccount(topology_st.standalone, "cn=not here," + DEFAULT_SUFFIX)
    with pytest.raises(ldap.INVALID_CREDENTIALS):
        # Bind as the entry which does not exist
        user.bind("some_password")

    # Test cn=config since it has its own code path
    user = UserAccount(topology_st.standalone, "cn=config")
    with pytest.raises(ldap.INVALID_CREDENTIALS):
        # Bind as the config entry which does not have a userpassword
        user.bind("some_password")

    user = UserAccount(topology_st.standalone, "cn=does not exist,cn=config")
    with pytest.raises(ldap.INVALID_CREDENTIALS):
        # Bind as an entry under cn=config that does not exist
        user.bind("some_password")


            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
            slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
        slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not exist");
        slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
            slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
            slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");