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:
- possible bug in fonction _local_getpw() and in openssh Cyril Diakhate (Feb 14)
- Re: possible bug in fonction _local_getpw() and in openssh Damien Miller (Feb 14)