|
|
ef1f48 |
From 861f17d2cb50fc649feee004be1ce08d2e3873f8 Mon Sep 17 00:00:00 2001
|
|
|
ef1f48 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
ef1f48 |
Date: Tue, 9 Feb 2021 14:02:59 -0500
|
|
|
ef1f48 |
Subject: [PATCH 4/4] Issue 4609 - CVE - info disclosure when authenticating
|
|
|
ef1f48 |
|
|
|
ef1f48 |
Description: If you bind as a user that does not exist. Error 49 is returned
|
|
|
ef1f48 |
instead of error 32. As error 32 discloses that the entry does
|
|
|
ef1f48 |
not exist. When you bind as an entry that does not have userpassword
|
|
|
ef1f48 |
set then error 48 (inappropriate auth) is returned, but this
|
|
|
ef1f48 |
discloses that the entry does indeed exist. Instead we should
|
|
|
ef1f48 |
always return error 49, even if the password is not set in the
|
|
|
ef1f48 |
entry. This way we do not disclose to an attacker if the Bind
|
|
|
ef1f48 |
DN exists or not.
|
|
|
ef1f48 |
|
|
|
ef1f48 |
Relates: https://github.com/389ds/389-ds-base/issues/4609
|
|
|
ef1f48 |
|
|
|
ef1f48 |
Reviewed by: tbordaz(Thanks!)
|
|
|
ef1f48 |
---
|
|
|
ef1f48 |
dirsrvtests/tests/suites/basic/basic_test.py | 72 +++++++++++++++++++-
|
|
|
ef1f48 |
ldap/servers/slapd/back-ldbm/ldbm_bind.c | 4 +-
|
|
|
ef1f48 |
ldap/servers/slapd/dse.c | 7 +-
|
|
|
ef1f48 |
3 files changed, 78 insertions(+), 5 deletions(-)
|
|
|
ef1f48 |
|
|
|
ef1f48 |
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
|
|
|
ef1f48 |
index e9afa1e7e..6244782fa 100644
|
|
|
ef1f48 |
--- a/dirsrvtests/tests/suites/basic/basic_test.py
|
|
|
ef1f48 |
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
|
|
|
ef1f48 |
@@ -13,7 +13,7 @@
|
|
|
ef1f48 |
|
|
|
ef1f48 |
from subprocess import check_output, PIPE, run
|
|
|
ef1f48 |
from lib389 import DirSrv
|
|
|
ef1f48 |
-from lib389.idm.user import UserAccounts
|
|
|
ef1f48 |
+from lib389.idm.user import UserAccount, UserAccounts
|
|
|
ef1f48 |
import pytest
|
|
|
ef1f48 |
from lib389.tasks import *
|
|
|
ef1f48 |
from lib389.utils import *
|
|
|
ef1f48 |
@@ -1062,6 +1062,76 @@ def test_search_ou(topology_st):
|
|
|
ef1f48 |
assert len(entries) == 0
|
|
|
ef1f48 |
|
|
|
ef1f48 |
|
|
|
ef1f48 |
+def test_bind_invalid_entry(topology_st):
|
|
|
ef1f48 |
+ """Test the failing bind does not return information about the entry
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ :id: 5cd9b083-eea6-426b-84ca-83c26fc49a6f
|
|
|
ef1f48 |
+ :customerscenario: True
|
|
|
ef1f48 |
+ :setup: Standalone instance
|
|
|
ef1f48 |
+ :steps:
|
|
|
ef1f48 |
+ 1: bind as non existing entry
|
|
|
ef1f48 |
+ 2: check that bind info does not report 'No such entry'
|
|
|
ef1f48 |
+ :expectedresults:
|
|
|
ef1f48 |
+ 1: pass
|
|
|
ef1f48 |
+ 2: pass
|
|
|
ef1f48 |
+ """
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ topology_st.standalone.restart()
|
|
|
ef1f48 |
+ INVALID_ENTRY="cn=foooo,%s" % DEFAULT_SUFFIX
|
|
|
ef1f48 |
+ try:
|
|
|
ef1f48 |
+ topology_st.standalone.simple_bind_s(INVALID_ENTRY, PASSWORD)
|
|
|
ef1f48 |
+ except ldap.LDAPError as e:
|
|
|
ef1f48 |
+ log.info('test_bind_invalid_entry: Failed to bind as %s (expected)' % INVALID_ENTRY)
|
|
|
ef1f48 |
+ log.info('exception description: ' + e.args[0]['desc'])
|
|
|
ef1f48 |
+ if 'info' in e.args[0]:
|
|
|
ef1f48 |
+ log.info('exception info: ' + e.args[0]['info'])
|
|
|
ef1f48 |
+ assert e.args[0]['desc'] == 'Invalid credentials'
|
|
|
ef1f48 |
+ assert 'info' not in e.args[0]
|
|
|
ef1f48 |
+ pass
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ log.info('test_bind_invalid_entry: PASSED')
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ # reset credentials
|
|
|
ef1f48 |
+ topology_st.standalone.simple_bind_s(DN_DM, PW_DM)
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+def test_bind_entry_missing_passwd(topology_st):
|
|
|
ef1f48 |
+ """
|
|
|
ef1f48 |
+ :id: af209149-8fb8-48cb-93ea-3e82dd7119d2
|
|
|
ef1f48 |
+ :setup: Standalone Instance
|
|
|
ef1f48 |
+ :steps:
|
|
|
ef1f48 |
+ 1. Bind as database entry that does not have userpassword set
|
|
|
ef1f48 |
+ 2. Bind as database entry that does not exist
|
|
|
ef1f48 |
+ 1. Bind as cn=config entry that does not have userpassword set
|
|
|
ef1f48 |
+ 2. Bind as cn=config entry that does not exist
|
|
|
ef1f48 |
+ :expectedresults:
|
|
|
ef1f48 |
+ 1. Fails with error 49
|
|
|
ef1f48 |
+ 2. Fails with error 49
|
|
|
ef1f48 |
+ 3. Fails with error 49
|
|
|
ef1f48 |
+ 4. Fails with error 49
|
|
|
ef1f48 |
+ """
|
|
|
ef1f48 |
+ user = UserAccount(topology_st.standalone, DEFAULT_SUFFIX)
|
|
|
ef1f48 |
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
|
|
ef1f48 |
+ # Bind as the suffix root entry which does not have a userpassword
|
|
|
ef1f48 |
+ user.bind("some_password")
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ user = UserAccount(topology_st.standalone, "cn=not here," + DEFAULT_SUFFIX)
|
|
|
ef1f48 |
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
|
|
ef1f48 |
+ # Bind as the entry which does not exist
|
|
|
ef1f48 |
+ user.bind("some_password")
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ # Test cn=config since it has its own code path
|
|
|
ef1f48 |
+ user = UserAccount(topology_st.standalone, "cn=config")
|
|
|
ef1f48 |
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
|
|
ef1f48 |
+ # Bind as the config entry which does not have a userpassword
|
|
|
ef1f48 |
+ user.bind("some_password")
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+ user = UserAccount(topology_st.standalone, "cn=does not exist,cn=config")
|
|
|
ef1f48 |
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
|
|
ef1f48 |
+ # Bind as an entry under cn=config that does not exist
|
|
|
ef1f48 |
+ user.bind("some_password")
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
+
|
|
|
ef1f48 |
@pytest.mark.bz1044135
|
|
|
ef1f48 |
@pytest.mark.ds47319
|
|
|
ef1f48 |
def test_connection_buffer_size(topology_st):
|
|
|
ef1f48 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
|
|
|
ef1f48 |
index fa450ecd5..38d115a32 100644
|
|
|
ef1f48 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_bind.c
|
|
|
ef1f48 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
|
|
|
ef1f48 |
@@ -76,8 +76,8 @@ ldbm_back_bind(Slapi_PBlock *pb)
|
|
|
ef1f48 |
case LDAP_AUTH_SIMPLE: {
|
|
|
ef1f48 |
Slapi_Value cv;
|
|
|
ef1f48 |
if (slapi_entry_attr_find(e->ep_entry, "userpassword", &attr) != 0) {
|
|
|
ef1f48 |
- slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
|
|
|
ef1f48 |
- NULL, 0, NULL);
|
|
|
ef1f48 |
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
|
|
|
ef1f48 |
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
CACHE_RETURN(&inst->inst_cache, &e);
|
|
|
ef1f48 |
rc = SLAPI_BIND_FAIL;
|
|
|
ef1f48 |
goto bail;
|
|
|
ef1f48 |
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
|
|
|
ef1f48 |
index 0e22d3cec..0d3268046 100644
|
|
|
ef1f48 |
--- a/ldap/servers/slapd/dse.c
|
|
|
ef1f48 |
+++ b/ldap/servers/slapd/dse.c
|
|
|
ef1f48 |
@@ -1443,7 +1443,8 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
|
|
|
ef1f48 |
|
|
|
ef1f48 |
ec = dse_get_entry_copy(pdse, sdn, DSE_USE_LOCK);
|
|
|
ef1f48 |
if (ec == NULL) {
|
|
|
ef1f48 |
- slapi_send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not exist");
|
|
|
ef1f48 |
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
return (SLAPI_BIND_FAIL);
|
|
|
ef1f48 |
}
|
|
|
ef1f48 |
|
|
|
ef1f48 |
@@ -1451,7 +1452,8 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
|
|
|
ef1f48 |
case LDAP_AUTH_SIMPLE: {
|
|
|
ef1f48 |
Slapi_Value cv;
|
|
|
ef1f48 |
if (slapi_entry_attr_find(ec, "userpassword", &attr) != 0) {
|
|
|
ef1f48 |
- slapi_send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Entry does not have userpassword set");
|
|
|
ef1f48 |
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
slapi_entry_free(ec);
|
|
|
ef1f48 |
return SLAPI_BIND_FAIL;
|
|
|
ef1f48 |
}
|
|
|
ef1f48 |
@@ -1459,6 +1461,7 @@ dse_bind(Slapi_PBlock *pb) /* JCM There should only be one exit point from this
|
|
|
ef1f48 |
|
|
|
ef1f48 |
slapi_value_init_berval(&cv, cred);
|
|
|
ef1f48 |
if (slapi_pw_find_sv(bvals, &cv) != 0) {
|
|
|
ef1f48 |
+ slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, "Invalid credentials");
|
|
|
ef1f48 |
slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
|
|
|
ef1f48 |
slapi_entry_free(ec);
|
|
|
ef1f48 |
value_done(&cv;;
|
|
|
ef1f48 |
--
|
|
|
ef1f48 |
2.26.2
|
|
|
ef1f48 |
|