COMMAND pw suite SYTEM AFFECTED FreeBSD PROBLEM The FreeBSD account administration pw suite is able to produce "random" passwords for new accounts. Due to the simplicity of the password generation algorithm involved, the passwords are easily predictable amid a particular range of possibilities. This range may be very narrow, depending on what sort of information is available to the attacker. The pid and the current time in seconds are ored (NOT xored) together and used as the seed. Because of this, the probability of a lower bit in the seed of being on is 3/4. The msb's of the seed change very slowly and predictably over time and in effect contain no entropy. If the attacker has access to the file system then the time the account was created on can by guessed very accurately by examining the creation date of the new account's directory, or the creation date of the new account's mail spool file. With the time part of the seed known it is then possible to generate an a mask to eliminate 50% of the remaining possible pid values. The pid can be further approximated retrospectively by correlation between time stamps and pid values from a wide number of file system sources such as the pid of the sendmail task used to deliver the new-user mail, to names of /tmp and queue files. An active attack (looking for the "pw" process or other signs of account creation) will of course locate the pid very closely, if not exactly. SOLUTION Patch addresses the problem is given by Julian A. (proff@suburbia.net) who originally described this vulnerability. --- /usr/src/usr.sbin/pw/pw_user.c.orig Thu Dec 12 02:10:47 1996 +++ /usr/src/usr.sbin/pw/pw_user.c Sat Dec 14 11:37:50 1996 @@ -33,6 +33,10 @@ #include #include #include +#include +#include +#include +#include #include "pw.h" #include "bitmap.h" #include "pwupd.h" @@ -738,19 +742,61 @@ return strcpy(buf, crypt(password, salt)); } +u_char * +pw_genmd5rand (u_char *d) /* cryptographically secure rng */ +{ + MD5_CTX md5_ctx; + struct timeval tv, tvo; + struct rusage ru; + int n=0; + int t; + MD5Init (&md5_ctx); + t=getpid(); + MD5Update (&md5_ctx, (u_char*)&t, sizeof t); + t=getppid(); + MD5Update (&md5_ctx, (u_char*)&t, sizeof t); + gettimeofday (&tvo, NULL); + do { + getrusage (RUSAGE_SELF, &ru); + MD5Update (&md5_ctx, (u_char*)&ru, sizeof ru); + gettimeofday (&tv, NULL); + MD5Update (&md5_ctx, (u_char*)&tv, sizeof tv); + } while (n++<20 || tv.tv_usec-tvo.tv_usec< 100*1000); + MD5Final (d, &md5_ctx); + return d; +} + +static u_char * +pw_getrand(u_char *buf, int len) +{ + int fd; + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1 || read(fd, buf, len)!=len) { + int n; + for (n=0;ndefault_password) { case -1: /* Random password */ srandom((unsigned) (time(NULL) | getpid())); l = (random() % 8 + 8); /* 8 - 16 chars */ + pw_getrand(rndbuf, l); for (i = 0; i