Creating NT4 Password Hashes

by Oct 11, 2019

Internally, Active Directory stores all passwords as so-called NTLM Hashes. There are a number of security-analysis tools that can read and dump these hashes.

While there fortunately is no feasible way of decrypting these hashes and retrieving the original passwords, you can take a (known) password and turn it into an NTLM hash yourself. This is the fundamental procedure of dictionary attacks: they take long lists of “known passwords”, turn them into NTLM hashes, and when they match an actual AD account hash, the password is known.

This way, your security department could take password blacklist with insecure passwords such as “P@ssw0rd”, turn them into NTLM hashes, and compare them to the password hashes of your Active Directory to identify accounts that need a password change.

Here is PowerShell code to turn a plain text into an NTLM hash:

function ConvertTo-NTLMPasswordHash
{
  #Work based on code found here: https://www.myotherpcisacloud.com/post/getmd4hash
  #Original Author: Ryan Ries, 2014 
  param(
    [Parameter(Mandatory=$true)][string]$password
  )

  Function Get-MD4Hash
  {
    Param ([Parameter(Mandatory=$True, ValueFromPipeline=$False)]          
    [Byte[]]$DataToHash)
           
      Set-StrictMode -Version Latest
      Add-Type -TypeDefinition @'
        using System;
        using System.Text;
        using System.Runtime.InteropServices;
        public class BCrypt
        {
            [DllImport("bcrypt.dll", CharSet = CharSet.Auto)]
            public static extern NTStatus BCryptOpenAlgorithmProvider(
                [Out] out IntPtr phAlgorithm,
                [In] string pszAlgId,
                [In, Optional] string pszImplementation,
                [In] UInt32 dwFlags);
 
            [DllImport("bcrypt.dll")]
            public static extern NTStatus BCryptCloseAlgorithmProvider(
                [In, Out] IntPtr hAlgorithm,
                [In] UInt32 dwFlags);
 
            [DllImport("bcrypt.dll", CharSet = CharSet.Auto)]
            public static extern NTStatus BCryptCreateHash(
                [In, Out] IntPtr hAlgorithm,
                [Out] out IntPtr phHash,
                [Out] IntPtr pbHashObject,
                [In, Optional] UInt32 cbHashObject,
                [In, Optional] IntPtr pbSecret,
                [In] UInt32 cbSecret,
                [In] UInt32 dwFlags);
 
            [DllImport("bcrypt.dll")]
            public static extern NTStatus BCryptDestroyHash(
                [In, Out] IntPtr hHash);
 
            [DllImport("bcrypt.dll")]
            public static extern NTStatus BCryptHashData(
                [In, Out] IntPtr hHash,
                [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
                [In] int cbInput,
                [In] UInt32 dwFlags);
 
            [DllImport("bcrypt.dll")]
            public static extern NTStatus BCryptFinishHash(
                [In, Out] IntPtr hHash,
                [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput,
                [In] int cbInput,
                [In] UInt32 dwFlags);
 
            [Flags]
            public enum AlgOpsFlags : uint
            {           
                BCRYPT_PROV_DISPATCH = 0x00000001,
                BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008,
                BCRYPT_HASH_REUSABLE_FLAG = 0x00000020
            }
 
            // This is a gigantic enum and I don't want to copy all of it into this Powershell script.
            // Basically anything other than zero means something went wrong.
            public enum NTStatus : uint
            {
                STATUS_SUCCESS = 0x00000000
            }
        }
'@
 
      [Byte[]]$HashBytes   = New-Object Byte[] 16
      [IntPtr]$PHAlgorithm = [IntPtr]::Zero
      [IntPtr]$PHHash      = [IntPtr]::Zero
      $NTStatus = [BCrypt]::BCryptOpenAlgorithmProvider([Ref] $PHAlgorithm, 'MD4', $Null, 0)
      If ($NTStatus -NE 0)
      {
        Write-Error "BCryptOpenAlgorithmProvider failed with NTSTATUS $NTStatus"
        If ($PHAlgorithm -NE [IntPtr]::Zero)
        {
          $NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
        }
        Return
      }
      $NTStatus = [BCrypt]::BCryptCreateHash($PHAlgorithm, [Ref] $PHHash, [IntPtr]::Zero, 0, [IntPtr]::Zero, 0, 0)
      If ($NTStatus -ne 0)
      {
        Write-Error "BCryptCreateHash failed with NTSTATUS $NTStatus"
        If ($PHHash -ne [IntPtr]::Zero)
        {
          $NTStatus = [BCrypt]::BCryptDestroyHash($PHHash)               
        }
        If ($PHAlgorithm -ne [IntPtr]::Zero)
        {
          $NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
        }
        Return
      }
 
      $NTStatus = [BCrypt]::BCryptHashData($PHHash, $DataToHash, $DataToHash.Length, 0)
      $NTStatus = [BCrypt]::BCryptFinishHash($PHHash, $HashBytes, $HashBytes.Length, 0)
 
      If ($PHHash -NE [IntPtr]::Zero)
      {
        $NTStatus = [BCrypt]::BCryptDestroyHash($PHHash)
      }
      If ($PHAlgorithm -NE [IntPtr]::Zero)
      {
        $NTStatus = [BCrypt]::BCryptCloseAlgorithmProvider($PHAlgorithm, 0)
      }
         
      $HashString = New-Object System.Text.StringBuilder
      Foreach ($Byte In $HashBytes)
      {
        $null = $HashString.Append($Byte.ToString("x2"))
      }
      $HashString.ToString()
    
  }
  Get-MD4Hash -DataToHash ([System.Text.Encoding]::Unicode.getBytes($password))
}

Twitter This Tip! ReTweet this Tip!