Re: [OFFTOPIC] Re: password encryption

Robert G. Brown (rgb@phy.duke.edu)
Thu, 5 Aug 1999 23:56:15 -0400 (EDT)


On Thu, 5 Aug 1999, Alan Curry wrote:

> Robert G. Brown writes the following:
> >
> >main(argc, argv)
> > int argc;
> > char **argv;
> > {
> > char *s,passwd[128],salt[8];
> > unsigned long i,iterations;
> >
> > if(argc != 3) {
> > fprintf(stderr, "usage: makepw passwd salt\n");
> > exit(1);
> > }
> > argv++;
> > sprintf(passwd,"%s",*argv);
>
> Buffer overflow waiting to happen

<Pow> Ugh. Got me right in the gut.

Perhaps I should explain.

First, I wrote this a LONG time ago (ten or fifteen years) for personal
use -- it isn't designed to be proof against buffer overwrites or the
like because it is strictly a userspace program, not a daemon and I
generally don't even run it as root as there is no need to.

Second, it was designed to generate "standard unix" passwd's which
(according to the man page) are only 8 characters significant.

Third, according to the crypt man page documentation ditto, it uses DES
encryption, not MD5, and the man page also states that the salt is only
two characters. Indeed, the salt is by convention the first two
characters of the /etc/passwd encrypted passwd field and the DES crypt
ignores more than eight characters in the input string and two in the
salt ANYWAY.

Fourth, very similar routines (perhaps less sloppily written:-) were
used in crack at the time I wrote this tiny utility code and may indeed
still be there.

SO, flame away, but recognize that for its purpose (use by ME to
generate DES encrypted passwd fields for a standard /etc/passwd file by
hand a decade ago) it works just fine. OK, so I was lazy and sloppy
using sprintf instead of strncpy and did no length checking...I was
younger then.

> > /* Truncate passwd at eight characters on general principles.*/
> > passwd[8] = 0;
>
> Wrong. MD5 passwords can be significant to a lot more than 8 chars.

But the standard unix passwd command available on most systems
(including those flavors of linux I've access to) only accept passwd's
with eight or fewer characters. On my nice new RH 6 install, it says
that the new passwd is "too similar to the old one" if I enter 10
characters none of which resemble those in my old one, but if I enter
only the first 8 it is happy. Obviously, it uses the DES crypt and not
MD5.

Perhaps the original poster wanted to generate MD5 passwds. On the
other hand, perhaps he (like me) just wanted to be able to build
encrypted passwd fields on demand to paste into a /etc/passwd file for
new users, perhaps in a simple script (I have another variant of the
same code that generates 1-N RANDOM new passwd's for the same purpose).

> > argv++;
> > sprintf(salt,"%s",*argv);
>
> Another buffer overflow waiting to happen
>
> > /* Truncate salt at two characters, ditto. */
> > salt[2] = 0;
>
> Wrong. MD5 salt is longer than 2 chars.
>
> > s=crypt(passwd,salt);
> > printf("%s\n",s);
> > exit(0);
> > }
>
> People, don't truncate things before passing them to crypt. It knows more
> than you do about the right lengths of passwords and salt.

True enough. If you don't truncate the strings at all, (and clean up
the code so it is buffer safe to protect you from segment faults in the
event that you enter way too many characters) then you get the following
behaviour:

gcc -O3 -lcrypt makepw.c -o makepw
rgb@rgb|T:30>>!./ma
./makepw frogfrog abcdef
abi219G9lnw4E
rgb@rgb|T:31>>./makepw frogfrogfrog abcdef
abi219G9lnw4E
rgb@rgb|T:32>>./makepw frogfrogfrog ab
abi219G9lnw4E

Note that crypt only keeps the first two characters of the salt and
ignores more than eight characters of the passwd field. Presumably if
you have replaced the standard DES crypt with an MD5 version, it will do
better than this, but when I wrote this little code snippet I didn't
have the MD5 version installed. I still don't. (IMHO) Most crack
attempts succeed not because of the weakness of the DES encryption but
rather because of the stupidity of users in choosing dumb passwd's that
are easy to crack. At some point in the not too distant future, of
course, we may all need to use MD5 (or any really slow and painful
variant of crypt) just to slow down the encyption to the point where
crack cannot exhaustively search all letter permutations, but this was
not the point of my posting the code snippet -- I was just trying to
illustrate the use of crypt in a practical frame.

Anyway, I humbly submit below a cleaned up version of the makepw program
that uses strncpy instead of sprintf and no longer has the truncation.
Since I don't have an MD5 crypt man page handy, I have no idea what the
maximum buffer lengths are that it will tolerate for passwd and salt,
but obviously if you do have that version of crypt you can read the man
pages and adjust the MAXPW and MAXSALT (which are vast overkill anyway,
in all probability, unless you like pass phrases and not pass words) to
whatever it likes.

rgb

Robert G. Brown http://www.phy.duke.edu/~rgb/
Duke University Dept. of Physics, Box 90305
Durham, N.C. 27708-0305
Phone: 1-919-660-2567 Fax: 919-660-2525 email:rgb@phy.duke.edu

/* %< Snip snip snip ======================================== */
#include <stdio.h>
#include <stdlib.h>

static char rcs_id[]="$Id: makepw.c,v 1.3 1999/08/06 03:51:06 rgb Exp $ (Robert G. Brown)";

char *crypt();
#define MAXPW 128
#define MAXSALT 128

main(int argc, char **argv)
{
char *s,passwd[MAXPW],salt[MAXSALT];

if(argc != 3) {
fprintf(stderr, "usage: makepw passwd salt\n");
exit(1);
}
/*
* Get the passwd field. Only the first eight characters matter to
* the standard DES crypt() routine.
*/
argv++;
strncpy(passwd,*argv,MAXPW);
/*
* Get the salt. Only the first two characters matter to the standard
* DES crypt() routine, and will be the first two characters of the
* output encrypted string s.
*/
argv++;
strncpy(salt,*argv,MAXSALT);
/*
* Make the passwd and print it out.
*/
s=crypt(passwd,salt);
printf("%s\n",s);
exit(0);

}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/