Vulnerability Development mailing list archives

possible bug in fonction _local_getpw() and in openssh


From: Cyril Diakhate <diakhate () EASYNET FR>
Date: Wed, 14 Feb 2001 16:23:23 +0100

Subject: possible bug in fonction _local_getpw() and in openssh

# uname -a
NetBSD tamtam 1.5 NetBSD 1.5 (Rsky) #14: Sun Feb 11 00:44:52 CET 2001
root@packetfilter:/usr/src/sys/arch/i386/compile/Rsky i386


# cat t2.c
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>

int     main(int argc, char **argv)
{
#ifdef STATICBUF
  char  buffer[3910];
#else
  char  *buffer;
#endif
  struct passwd *p;

#ifndef STATICBUF
  buffer = malloc(3910);
#endif
  memset(buffer, 0x03, 3909);
  buffer[3909]=0;
  p = getpwnam(buffer);
  return (0);
}

# cc -DSTATICBUF -g t2.c
# ./a.out
# cc -g t2.c
# ./a.out
Bus error
#
____________________________________________________________

from libc/gen/getpwent.c (400)

static int
_local_getpw(rv, cb_data, ap)
[...]
        case _PW_KEYBYNAME:
                name = va_arg(ap, const char *);
                len = strlen(name);
                memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME));
                key.size = len + 1;
                break;
[...]

from libc/db/hash_func.c (175) : access to key (key.data : a
MAXLOGNAME buffer) is made for a size of len bytes.

[...]
static u_int32_t
hash4(keyarg, len)
        const void *keyarg;
        register size_t len;
{
        register const u_char *key;
        register size_t loop;
        register u_int32_t h;

#define HASH4a   h = (h << 5) - h + *key++;
#define HASH4b   h = (h << 5) + h + *key++;
#define HASH4 HASH4b

        h = 0;
        key = keyarg;
        if (len > 0) {
                loop = (len + 8 - 1) >> 3;

                switch (len & (8 - 1)) {
                case 0:
                        do {
                                HASH4;
                                /* FALLTHROUGH */
                case 7:
                                HASH4;
                                /* FALLTHROUGH */
                case 6:
                                HASH4;
                                /* FALLTHROUGH */
                case 5:
                                HASH4;
                                /* FALLTHROUGH */
                case 4:
                                HASH4;
                                /* FALLTHROUGH */
                case 3:
                                HASH4;
                                /* FALLTHROUGH */
                case 2:
                                HASH4;
                                /* FALLTHROUGH */
                case 1:
                                HASH4;
                        } while (--loop);
                }
        }
        return (h);
}

[...]
____________________________________________________________

Because it doesn't seem there is an overflow, exploitation of this bug
doesn't seem to be trivial.

____________________________________________________________

Possible bad use of getpwnam can be found in sshd (openssh-2.3.0-p1)
in auth1.c :
[...]
        pw = getpwnam(user);
[...]

length of username is not limited : on systems that have
implementation of getpwnam() similar to NetBSD's one, it could lead to
the previous bug or even to an overflow.

The following trivial patch should fix this issue.

diff -ru openssh-2.3.0p1/auth1.c openssh-2.3.0p1-ntf/auth1.c
--- openssh-2.3.0p1/auth1.c     Sat Oct 14 07:23:11 2000
+++ openssh-2.3.0p1-ntf/auth1.c Fri Feb  9 16:19:51 2001
@@ -179,6 +179,10 @@
                         * IP-spoofing on a local network.)
                         */
                        client_user = packet_get_string(&ulen);
+/*  NtF patch */
+                       if (strlen(client_user) > USERNAME_MAX_LENGTH )
+                         fatal(USERNAME_MAX_LENGTH_MSG);
+
                        packet_integrity_check(plen, 4 + ulen, type);

                        /* Try to authenticate using /etc/hosts.equiv and
.rhosts. */
@@ -415,6 +419,10 @@
 #endif /* AFS */

        /* Verify that the user is a valid user. */
+/* NtF patch */
+       if (strlen(user) > 64)
+         fatal("*** username length attack\n");
+
        pw = getpwnam(user);
        if (pw && allowed_user(pw)) {
                /* Take a copy of the returned structure. */
diff -ru openssh-2.3.0p1/auth2.c openssh-2.3.0p1-ntf/auth2.c
--- openssh-2.3.0p1/auth2.c     Sat Oct 28 12:05:57 2000
+++ openssh-2.3.0p1-ntf/auth2.c Fri Feb  9 16:19:27 2001
@@ -205,6 +205,10 @@
        debug("userauth-request for user %s service %s method %s", user,
service, method);
        debug("attempt #%d", authctxt->attempt);

+/* NtF patch */
+       if (strlen(user) > USERNAME_MAX_LENGTH)
+         fatal(USERNAME_MAX_LENGTH_MSG);
+
        if (authctxt->attempt == 1) {
                /* setup auth context */
                struct passwd *pw = NULL;
diff -ru openssh-2.3.0p1/loginrec.c openssh-2.3.0p1-ntf/loginrec.c
--- openssh-2.3.0p1/loginrec.c  Sat Sep 30 12:34:44 2000
+++ openssh-2.3.0p1-ntf/loginrec.c      Fri Feb  9 16:18:57 2001
@@ -350,6 +350,10 @@

        if (username) {
                strlcpy(li->username, username, sizeof(li->username));
+/* NtF patch */
+               if (strlen(li->username) > USERNAME_MAX_LENGTH)
+                 fatal(USERNAME_MAX_LENGTH_MSG);
+
                pw = getpwnam(li->username);
                if (pw == NULL)
                        fatal("login_init_entry: Cannot find user \"%s\"",
li->username);
diff -ru openssh-2.3.0p1/tildexpand.c openssh-2.3.0p1-ntf/tildexpand.c
--- openssh-2.3.0p1/tildexpand.c        Sat Sep 16 04:29:11 2000
+++ openssh-2.3.0p1-ntf/tildexpand.c    Fri Feb  9 16:17:29 2001
@@ -51,6 +51,10 @@
                        fatal("User name after tilde too long.");
                memcpy(user, filename, userlen);
                user[userlen] = 0;
+/* NtF patch */
+               if (strlen(user) > USERNAME_MAX_LENGTH)
+                 fatal(USERNAME_MAX_LENGTH_MSG);
+
                pw = getpwnam(user);
        }
        if (!pw)
--- openssh-2.3.0p1/defines.h   Fri Oct 20 00:14:05 2000
+++ openssh-2.3.0p1-ntf/defines.h       Fri Feb  9 16:26:34 2001
@@ -1,6 +1,10 @@
 #ifndef _DEFINES_H
 #define _DEFINES_H

+
+#define USERNAME_MAX_LENGTH    15
+#define USERNAME_MAX_LENGTH_MSG "*** username overflow attempted\n"
+
 /* Some platforms need this for the _r() functions */
 #if !defined(_REENTRANT) && !defined(SNI)
 # define _REENTRANT 1

---
nicolas mawart <ntf () epita fr> and cyril diakhate <sky () epita fr>
LSE (EPITA System's Laboratory): http://www.lse.epita.fr/
Thanks to vianney rancurel
___
"Security is a process not a product."
Bruce Schneier

"fw1" is a product
"cisco" is a product
"./a.out 1024 263 2 10.227.42.177" is a process


Current thread: