Bug 643227 (CVE-2011-0002) - CVE-2011-0002 libuser creates LDAP users with a default password
Summary: CVE-2011-0002 libuser creates LDAP users with a default password
Keywords:
Status: CLOSED ERRATA
Alias: CVE-2011-0002
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 668016 668017 668018 668019 668020 668021 668534 822045
Blocks:
TreeView+ depends on / blocked
 
Reported: 2010-10-15 00:02 UTC by Miloslav Trmač
Modified: 2019-09-29 12:40 UTC (History)
11 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of: 643022
Environment:
Last Closed: 2012-06-20 17:12:18 UTC
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Product Errata RHSA-2011:0170 0 normal SHIPPED_LIVE Moderate: libuser security update 2011-01-20 16:33:00 UTC

Description Miloslav Trmač 2010-10-15 00:02:05 UTC
+++ This bug was initially created as a clone of Bug #643022 +++

<snip>
Also when I do not specify the password when creating the user (with -p), some kind of "default" string appears in password:

# luseradd tst

ldap search listing (see the user pass):
# tst, omoris, free, gold.testday
dn: uid=tst,ou=omoris,ou=free,dc=gold,dc=testday
uidNumber: 503
uid: tst
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
shadowExpire: -1
homeDirectory: /home/tst
loginShell: /bin/bash
shadowInactive: -1
userPassword:: ISE=
[snip]

--- Additional comment from mitr on 2010-10-14 11:58:39 EDT ---

<snip>

The "userPassword:: ISE=" value decodes to '!!', which should [not] let the user to log in, per RFC 2307.

Comment 1 Miloslav Trmač 2010-10-15 00:13:04 UTC
The comment above is correct WRT RFC 2307 - i.e. using only nss_ldap and using NSS to read the shadow entry and authenticate against it: in that case the RFC 2307 prohibition of unprefixed values means the shadow password returned is always "*".

This is, unfortunately, not general enough - when using pam_ldap on a client (or when connecting to the LDAP server using the LDAP protocol, and perhaps in other cases), the generic definition of "userPassword" (RFC 4519) applies, and the "!!" values is considered a plaintext password that can be used to succesfully log in, at least when the server is openldap (I haven't checked against 389).


Impact: (luseradd) without specifying a password creates an user account that can, under some circumstances, be used to log in using a default password.  In usual cases, the password would be set either in the initial luseradd invocation, or in a following lpasswd invocation, leaving at most a short window when the "!!" value can be used.  It is possible, however, to enter "system" accounts into LDAP for which the password is never set; in such cases the default password could persist for indefinite time.  This would argue for a rather high vulnerability severity rating.

AFAICS the bug has been in libuser for a very long time, since RHEL 3 at least.


I have Cc:ed LDAP server maintainers to this bug - could you please verify my understanding of the situation?

Comment 4 Vincent Danen 2010-10-15 17:42:42 UTC
Adding Nalin as the pam_ldap maintainer as he might have some good ideas about where the fault lies.

Comment 7 Miloslav Trmač 2010-10-15 18:54:35 UTC
pam_ldap is not at fault.

There are three basic ways to authenticate an user defined in LDAP:
- Load the encrypted password from the LDAP server to the client, verify
  password locally.

  This is what nss_ldap without pam_ldap does, an it seems to be fine.

- Try to authenticate to the LDAP server using the provided password.

  This is what pam_ldap does (by definition), and "!!" may work.  This depends
  on server capabilities and configuration, but we already know that at least
  openssl can treat the password as unencrypted.

  Note that pam_ldap can not filter out "!!" - it really may be a legitimate
  password.  All policy is in the LDAP server in this scenario.

- Use an independent authentication mechanism, e.g. Kerberos.  In this case
  the userPassword value is irrelevant.

I wasn't able to figure out from sssd-ldap(5) what pam_sss uses.

Usually, Kerberos is preferred to pam_ldap with TLS, which is preferred to nss_ldap without pam_ldap.  But any of these configurations is "valid" and may be used by our users in production setups.

Also note that regardless of the authentication mechanism used to log in users to client computers, "!!" may remain a valid password for the user to log in to the LDAP server directly.  The server administrator needs to set up ACLs to restrict what users can change, regardless of the libuser problem - but there are some unauthorized access scenarios, for example an attacker might connect to the LDAP server using the "!!" password and change the user's password to something else.


AFAICS the only place where this can be fixed is libuser.  Changing userdefaults/lU_USERPASSWORD to "{crypt}!!" is an acceptable workaround if the "ldap" module is used - otherwise this value is not defined, although it would work in practice.  A correct fix would be to use the "{crypt}!!" value internally in the LDAP module.

There is a theoretical case where libuser is used to create the user record both locally and in LDAP - in that case there is no 100% correct solution in the libuser model because it cannot use a different value for different modules.

Comment 8 Miloslav Trmač 2010-10-15 18:56:16 UTC
Please disregard lpasswd - it is attempting to authenticate using the local PAM configuration as the target user; this does not make much sense, but it is also not really relevant to the primary issue.

Comment 9 Nalin Dahyabhai 2010-10-15 19:04:11 UTC
(In reply to comment #4)
> Adding Nalin as the pam_ldap maintainer as he might have some good ideas about
> where the fault lies.

The pam_ldap password check is done by attempting an LDAP bind, so the comparison with the user-supplied value is performed at the server.  The check for '!!' is done in pam_unix during the auth phase, so other modules aren't going to heed it.  If the server supports checking {CRYPT} passwords, then I agree that always using {CRYPT} is the best route.  I'm just not certain that all servers do support it.  If we can just omit a default 'userPassword' value without breaking anything, that might be an alternative.

Comment 10 Vincent Danen 2010-10-18 15:36:38 UTC
If we have libuser set _no_ password by default, what will happen?  Will that allow a LDAP-based user to authenticate without a password?  What about a local user?

If libuser is using shadow/passwd, and we set the default to {crypt}!!, will the local system treat that the same as !! and prevent logins?

Comment 11 Jan Vcelak 2010-10-18 16:11:09 UTC
(In reply to comment #10)
> If we have libuser set _no_ password by default, what will happen?

OpenLDAP disallows unauthenticated binds by default. Therefore pam_ldap should fail.

ldap_bind: Server is unwilling to perform (53)
        additional info: unauthenticated bind (DN with no password) disallowed

But it can be enabled with 'olcAllows: bind_anon_dn' in cn=config. If somebody needs this configuration, {crypt}!! as a default password will be safe way.

Comment 12 Miloslav Trmač 2010-10-18 21:09:07 UTC
Setting no userPassword attribute seems to be the cleanest LDAP solution, and reading the code, the rest of the system would probably handle it fine (nss_ldap uses "*" if userPassword is not present, nss_sss uses "*" regardless of userPassword value).  Internally in libuser, I'm rather worried that removing the default value could break applications - dereferencing an unexpected NULL value.


As for LDAP servers that do not support {crypt}, libuser uses {crypt} everywhere, so if using libuser makes any sense at all, {crypt} is supported.


The case of libuser modifying both LDAP and passwd/shadow at once is a semantic mess... if the value of pw_passwd from /etc/passwd and userPassword from LDAP are different (as they almost always are), the LU_USERPASSWORD value returned by libuser is always wrong.  This is the mirror image of our problem, that there is no single correct default value of the LU_USERPASSWORD attribute.

In addition to the above-discussed "!!" value, the shadow module can set userPassword to "x".  The value actually set by libuser depends on module ordering in libuser.conf.


In general, libuser is at various internal stages of user creation (user_default, user_add) not able to distinguish between "!!"/"x" specified by the user (intended to be a raw userPassword value) and "!!"/"x" set up by default (intended to be a crypt(2) hash matching no input).


Considering that both "!!" and "x" are rather ridiculous values for a plaintext password, I think it would make most sense to do an ugly hack inside the LDAP module, and replace both "!!" and "x" by "{crypt}!!", _only_ when _adding_ an user.  Any other value would be passed through unchanged:

- The default value of LDAP userPassword would not allow logins
- Applications that use libuser and set an explicit, LDAP-formatted,
  userPassword value would continue to work (except for unencrypted "x" and
  "!!")
- All LDAP-formatted userPassword modifications done using the libuser
  "*_modify" operation would continue to work unchanged
- libuser password change operations (*_setpass *) would continue to work.
  (This - i.e. lu_user_add() + lu_user_setpass() - is the recommended method,
  and is used by luseradd(8).)  In particular, this would continue to work
  even in the combined LDAP + /etc/passwd + /etc/shadow scenario.
- The "{crypt}!!" value won't appear in /etc/passwd and /etc/shadow
  (and in particular, /etc/passwd will contain the correct "x" marker for
  shadow passwords).

What do you all think?

Comment 13 Vincent Danen 2010-10-21 20:24:19 UTC
This sounds like it would work and solve the problem, yes.

At this point I suspect we will be calling this a security vulnerability and will need to assign a CVE name to it.

Is the fix for this going to be fairly intrusive, or something we can easily backport?  We'll need to fix libuser across the board for this.

I do think this is a fairly low impact issue as it requires using LDAP with libuser and creating a user without an initial password provided.

A preliminary CVSSv2 score for this would be 2.6/AV:L/AC:H/Au:N/C:P/I:P/A:N (based on the creation of the account with '!!' as the password as opposed to being able to log into an account with that password set since the vulnerability is in the creation of such accounts).

As such, I think we could safely defer this for some older products, but it might be wise to get this fix into Fedora and RHEL6 where new installations would lead to more creation of user accounts than older/more-established installations where adding new users would not be as common an occurrence.

Thoughts?

Comment 16 Stephen Gallagher 2010-10-28 18:21:20 UTC
For the record, since I don't think it was answered clearly above:

When 'ldap' is selected as the authentication provider in SSSD, it performs an LDAP bind the same way that pam_ldap.so does. Therefore, if the server would validate that as an acceptable password, SSSD would too.

The fact that SSSD didn't in your above example is unexpected. I also note that the secure.log reported (System error) in that case, which is actually not the same as rejecting it. That actually means that something went wrong in SSSD internally and we took the route of most-secure response (to deny).

I'll need to do some testing to figure out why that happened.

Comment 17 Vincent Danen 2010-10-28 19:31:29 UTC
(In reply to comment #16)
> The fact that SSSD didn't in your above example is unexpected. I also note that
> the secure.log reported (System error) in that case, which is actually not the
> same as rejecting it. That actually means that something went wrong in SSSD
> internally and we took the route of most-secure response (to deny).
> 
> I'll need to do some testing to figure out why that happened.

Could it not be due to lack of kerberos credentials on that test account?

Comment 18 Stephen Gallagher 2010-10-28 19:35:58 UTC
(In reply to comment #17)
> (In reply to comment #16)
> > The fact that SSSD didn't in your above example is unexpected. I also note that
> > the secure.log reported (System error) in that case, which is actually not the
> > same as rejecting it. That actually means that something went wrong in SSSD
> > internally and we took the route of most-secure response (to deny).
> > 
> > I'll need to do some testing to figure out why that happened.
> 
> Could it not be due to lack of kerberos credentials on that test account?

It could be. Was SSSD configured to use Kerberos for authentication, or LDAP? If it was configured for Kerberos, and that user didn't exist on the KDC, then that might explain it. Though it should still be returning denied rather than error.

Comment 40 Vincent Danen 2011-01-10 18:27:33 UTC
This is now public via 0.57 release:

https://fedorahosted.org/libuser/browser/NEWS?rev=libuser-0.57

Comment 41 Vincent Danen 2011-01-10 18:29:11 UTC
Created libuser tracking bugs for this issue

Affects: fedora-all [bug 668534]

Comment 42 Vincent Danen 2011-01-15 03:40:30 UTC
A script similar to the following could be used to see if any passwords do not start with {CRYPT} and would need to be updated/changed:


#!/usr/bin/python

import ldap

l = ldap.initialize("ldap://server")
#l.simple_bind_s("cn=Manager,dc=server", "password")

results = l.search_s("dc=server", ldap.SCOPE_SUBTREE, "(userPassword=*)",
["userPassword"])
for dn, attributes in results:
        if not attributes["userPassword"][0].startswith("{CRYPT}"):
                print dn

#l.unbind_s()

Comment 43 Tomas Hoger 2011-01-18 09:23:20 UTC
(In reply to comment #42)
> l = ldap.initialize("ldap://server")
> #l.simple_bind_s("cn=Manager,dc=server", "password")

Just to clarify, it's not uncommon to restrict access to userPassword attribute, so the connection is likely to need to bind using a sufficiently privileged user account.  Directory Manager account is such example.  Details depend on the ACL settings of each LDAP instance.

>         if not attributes["userPassword"][0].startswith("{CRYPT}"):
>                 print dn

This should also report accounts with userPassword using different hash.  {SSHA} is commonly used and default for RHDS, for example.  Depending on the goal, this can be modified to search for all accounts with plain text passwords, or only compare to the default password '!!' created by libuser.

Comment 44 errata-xmlrpc 2011-01-20 16:33:07 UTC
This issue has been addressed in following products:

  Red Hat Enterprise Linux 6
  Red Hat Enterprise Linux 5
  Red Hat Enterprise Linux 4

Via RHSA-2011:0170 https://rhn.redhat.com/errata/RHSA-2011-0170.html


Note You need to log in before you can comment on or make changes to this bug.