Old-style Windows NT LM hash recovery

From Computers Wiki
Jump to navigationJump to search

Old-style Windows NT LM hash recovery, specifically for the pre-NT4 SP3 world, does not seem to be documented. I recently had to figure this out for recovering the Administrator password for the Motorola Net6200/166, which was running the PowerPC version of Windows NT 4.0 SP2. I hope this information can be useful for others.

Attempted tools

The following tools were attempted to be used to recover the LM hash for the Administrator account. All of them either bombed out with an error message or crashed.

  • Cain & Abel v4.9.56
    • "SAM account's F value has a wrong size"
  • chntpw version 1.00 140201
    • "** No LANMAN hash found either. Try login with no password!"
  • creddump ed95e1a9a920e04733a2950f7de0ff5bdfec631c (specifically, pwdump.py)
    • incorrectly returns the null LM hash
  • impacket 0.11.0 (specifically, secretsdump.py)
    • "TypeError: 'NoneType' object is not subscriptable"

The crux of the incompatibility appears to be that Microsoft changed the format of the structures in SAM in NT4 SP3 to add support for the then-new Syskey utility, adding another layer of encryption provided by a boot key. This boot key is stored in the registry by default, but Syskey can require it to be entered upon boot. The old SAM format does not have any concept of this, but the four tested tools all expect it to exist.

Manual recovery

  1. Obtain an offline registry editor. I used Registry Spy 1.1.0 by Andy Smith.[1]
    1. sudo apt install libxcb-cursor0
    2. python3 -m venv env
    3. source env/bin/activate
    4. python3 setup.py install
    5. registryspy
  2. Get a copy of %WINDIR%\System32\Config\SAM from the pre-NT4 SP3 machine.
  3. Navigate to \SAM\Domains\Account\Users\000001F4. This represents the Administrator account. 000001F4 is its ID (decimal 500).
  4. Copy the 32nd last to 16th last bytes of the hexadecimal view of V somewhere, without whitespace. This should be your encrypted LM hash. Mine looked like this: 09e72baf281e2a2e00092899a8cb74f3
  5. Compute the little-endian representation of the account's ID. For the Administrator account, this will be: f4 01 00 00
  6. Repeat this representation three and a half times, to get fourteen bytes. Split this in half to get two 56-bit DES keys.
    1. For the example account, Key 1 will be: f4 01 00 00 f4 01 00
    2. For the example account, Key 2 will be: 00 f4 01 00 00 f4 01
  7. Split the encrypted LM hash into two 8-byte chunks.
    1. For the example account, Chunk 1 is: 09e72baf281e2a2e
    2. For the example account, Chunk 2 is: 00092899a8cb74f3
  8. DES-decrypt Chunk 1 with Key 1 and Chunk 2 with Key 2, then concatenate both decrypted chunks. This is your decrypted LM hash. Mine looked like this: ae6e1b1fccb24d5b944e2df489a880e4
    1. As a quick-and-dirty solution, I took the Wine implementation of DES,[2] removed the two #include statements, and appended this:
      #include <stdio.h>
      #include <stdlib.h>
      int main(int argc, char *argv[])
      	char *k1 = "\xf4\x01\x00\x00\xf4\x01\x00";
      	char *k2 = "\x00\xf4\x01\x00\x00\xf4\x01";
      	char *in1 = "\x09\xe7\x2b\xaf\x28\x1e\x2a\x2e";
      	char *in2 = "\x00\x09\x28\x99\xa8\xcb\x74\xf3";
      	char out1[8];
      	char out2[8];
      	CRYPT_DESunhash(out1, k1, in1);
      	CRYPT_DESunhash(out2, k2, in2);
      	for (int i = 0; i < 8; i++)
      		printf("%x", (unsigned char)out1[i]);
      	for (int i = 0; i < 8; i++)
      		printf("%x", (unsigned char)out2[i]);
      	return EXIT_SUCCESS;
  9. Create a text file named hashes.txt that contains the decrypted LM hash in a colon-delimited format.
    1. An example looks like this: Administrator:500:ae6e1b1fccb24d5b944e2df489a880e4::::
  10. Run hashcat -m 3000 -a 3 hashes.txt to recover the password.
    1. If you have a GPU, this will execute in the order of seconds.
    2. If you do not have a GPU, this will execute in the order of tens of minutes.
  11. Run hashcat -m 3000 -a 3 hashes.txt --show to see the password.
    1. Do not trust the password output of the command from the previous step. It will only show the recovered password for the first half of the LM hash even though both halves were recovered and needed to successfully login.
    2. The output will be in LM Hash : Uppercase Password format, like this: ae6e1b1fccb24d5b944e2df489a880e4:COMPUTER
  12. Take the uppercase password and attempt to login to the pre-NT4 SP3 machine with some permutation of casing.
    1. While the LM hash is computed from an uppercase version of the password, the machine might still need the correct casing in order to login. For me, the correct casing was computer.
    2. It is likely best to attempt all-uppercase, all-lowercase, and sentence-case versions first, before brute-forcing all 2^n possibilities, where n is the count of alphabetical characters in the recovered password.