Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 13 Dec 2018 08:46:56 +0100
From: Salva Peiró <speirofr@...il.com>
To: solar@...nwall.com
Cc: oss-security@...ts.openwall.com
Subject: Re: CVE Request: mini-httpd (<= v1.30) is affected by
 a response discrepancy information exposure (CWE-204)

Hi there,

Thanks for the pointers for further investigating,

I was also curious about why crypt(3) was returning NULL,
when I looked at the crypt(3) man-page I found that crypt()
returns NULL on error, upon further checking I've observed that
errno is being set to EINVAL (22) after the call to crypt(3).

So here is what I've done so far to reproduce this,
initially, I omitted the steps to generate the htpasswd
as I though they where not relevant, I'm adding them now for completeness:

The htpasswd password for the "user" is generated by htpasswd from
apache2-utils:amd64 (= 2.4.25-3+deb9u6) on Debian

# Generate password "user" for "user"
$ /usr/bin/htpasswd -c auth/.htpasswd user
New password: <user>
Re-type new password: <user>
Adding password for user user

$ cat  auth/.htpasswd
user:$apr1$5.vGoLoA$OrxfML2lNUHvhMJrIC7lP.

Then a request is made to mini-httpd:

$ curl http://user@....0.0.1:8000/auth/

This causes the mini-httpd to invoke crypt(3) with the following arguments
cryptpass = crypt(key, salt), I've added printf's to mini_httpd.c to report
the actual
arguments being passed and the value returned by crypt():

$ mini_httpd -D -p 8000 -h 127.0.0.1 -l /dev/stderr
key "" salt $apr1$Eh4Xgu3L$YIbNfgDcC1bRGBQWKMS.A1 cryptpass (null)
errno 22 strerror Invalid argument

Then mini_httpd.c receives a SIGSEGV when performing strcmp() on the NULL
cryptpass at mini_httpd.c:2407. The cause of the NULL return value is that
the salt given to crypt() is invalid as show by errno=EINVAL.  So crypt(3)
is setting
errno=EINVAL to report that the htpasswd file generated by apache2-utils is
not
valid for being used with mini_httpd.

Best,
--
salva

On Wed, Dec 12, 2018 at 5:33 PM Solar Designer <solar@...nwall.com> wrote:

> On Wed, Dec 12, 2018 at 04:27:02PM +0100, Salva Peir?? wrote:
> > The mini-httpd daemon (version <= v1.30) shipped in Debian/Ubuntu from
> [1]
> > is affected by a response discrepancy information exposure (CWE-204) that
> > enables an attacker to remotely enumerate valid htpasswd usernames (RFC
> > 7617).
> >
> > A more detailed advisory can be found at:
> > https://speirofr.appspot.com/files/advisory/SPADV-2018-01.md
> > https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916190
>
> The advisory SPADV-2018-01.md is in fact significantly more detailed
> than what you posted, so I've attached it to this message for archival.
>
> > Is there a CVE for this? If not, could one be assigned, please?
>
> oss-security is no longer a place to request CVE IDs.  See:
>
>
> https://oss-security.openwall.org/wiki/mailing-lists/oss-security#cve-requests
>
> "Previously, one could request CVE IDs for issues in Open Source
> software from oss-security.  This is no longer the case.  Instead,
> please start by posting about the (to be made) public issue to
> oss-security (without a CVE ID), request a CVE ID from MITRE directly,
> and finally "reply" to your own posting when you also have the CVE ID to
> add.  With the described approach you would only approach MITRE after
> the issue is already public, but if you choose to do things differently
> and contact MITRE about an issue that is not yet public, then please do
> not disclose to them more than the absolute minimum needed for them to
> assign a CVE ID."
>
> You've already posted in here (great!) so all that's left is for you to
> request a CVE ID from MITRE and to post that CVE ID here as a "reply".
>
> However, I question the vulnerability finding or at least its
> completeness, so you might want to hold off on requesting a CVE ID for
> it.  Please see below:
>
> > +++ b/mini_httpd.c
> > @@ -2404,7 +2404,8 @@ auth_check( char* dirname )
> >          /* Yes. */
> >          (void) fclose( fp );
> >          /* So is the password right? */
> > -        if ( strcmp( crypt( authpass, cryp ), cryp ) == 0 )
> > +        char *cryptpass = crypt( authpass, cryp );
> > +        if ((cryptpass != NULL) && (strcmp(cryptpass, cryp ) == 0) )
>
> While it's important to check the return from crypt(3) for non-NULL
> before using the string(*), if this were the issue triggering the
> vulnerability you describe that fix would be incomplete.
>
> (*) A general issue that was discussed in here some years ago, with
> opinions varying on whether crypt(3) should follow current POSIX and
> return NULL or retain historical behavior of never returning NULL not to
> upset programs written before the POSIX change.  In the end, many libc's
> went with the NULL returns on error.  Programs need to be fixed to
> support NULL returns from crypt(3) anyhow.
>
> In the advisory, you wrote:
>
> > When the basic authentication string "user:pass" is composed only of the
> user
> > part without the password part, ie. "user:", then the authpass at
> > mini_httpd.c:2372 becomes the empty string "".
> > When the empty string is passed to the crypt(3) this returns the NULL
> string.
> > The NULL string is later dereferenced by the strcmp(3) call at
> mini_httpd.c:2407
> > causing an invalid memory access that triggers the SIGSEGV, and kills
> the forked process.
>
> This isn't a complete explanation.  crypt(3) isn't supposed to return
> NULL when authpass is the empty string "".  Empty string is a valid
> password, and should result in a valid password hash string, as long as
> the salt or setting string provided in the second argument to crypt(3)
> is valid.
>
> I can see how you'd trigger a NULL return from crypt(3) by having an
> empty or otherwise invalid password hash string in the .htpasswd file.
> So you'd be able to distinguish usernames corresponding to those lines
> with invalid hashes from usernames corresponding to lines with valid
> hashes.  A crash on an invalid .htpasswd line is indeed a robustness
> bug, but I'm not sure it constitutes a vulnerability.
>
> This is different from being able to distinguish existing vs.
> non-existent usernames.  (Besides, when fixing an issue of the kind you
> thought this one was, we should also remember that timing leaks will
> remain either way.  I don't suggest to leave worse-than-timing leaks
> intact, but rather not to provide wrong expectations and a false sense
> of security once we do.  And a next step may be to reduce timing leaks
> by performing dummy password hashing for non-existent usernames, again
> being careful to point out that smaller timing leaks will remain.)
>
> If the behavior is in fact exactly as you observed it, then maybe your
> system's libc or libcrypt is vulnerable in that it's incapable of
> processing an empty password.  I almost wonder if someone thought it'd
> be OK to implement e.g. some security standardization compliance by
> having crypt(3) fail to process an empty password and return NULL.  If
> so, that would be an interesting case for us to discuss.
>
> Please investigate this further.
>
> Thanks,
>
> Alexander
>

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.