Last active
March 15, 2019 13:10
-
-
Save IISResetMe/50376918042912fecc5ff1402e1b7dbe to your computer and use it in GitHub Desktop.
LMHash generator in written in PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-WeakDESEncryptor { | |
<# | |
.SYNOPSIS | |
Creates a DESCryptoProviderService encryptor from a potentially unsafe key | |
.DESCRIPTION | |
DESCryptoProviderService.GetEncryptor() attempts to ensure that 0-keys can't be used. This function bypasses the protection and creates a DES encryptor from a potentially unsafe key and an empty initialization vector | |
.EXAMPLE | |
PS C:\> $DESProvider = [System.Security.Cryptography.DESCryptoServiceProvider]::new() | |
PS C:\> $encryptor = Get-WeakDESEncryptor -CSP $DESProvider -Key @(,0*8) | |
In this example a DESCryptoServiceProvider is instantiated and passed to Get-WeakDESEncryptor along with a weak key. $encryptor is assigned the corresponding encryptor | |
.OUTPUTS | |
System.Security.Cryptography.ICryptoTransform | |
.NOTES | |
For research purposes only | |
#> | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] | |
[System.Security.Cryptography.DESCryptoServiceProvider]$CSP, | |
[Parameter(Mandatory = $false, Position = 1)] | |
[byte[]]$Key, | |
[Parameter(Mandatory = $false)] | |
[byte[]]$InitVector = @(, 0 * 8) | |
) | |
if (-not $PSBoundParameters.ContainsKey('Key')) { | |
# Key not explicitly passed, inherit the key attached to the provider | |
$Key = $CSP.Key | |
} | |
# Locate the private method that creates a new encryptor | |
$encCreateMethod = $CSP.GetType().GetMethod("_NewEncryptor", [System.Reflection.BindingFlags]'NonPublic,Instance') | |
# Prepare method parameters | |
$encParams = @($key, $CSP.Mode, $InitVector, $CSP.FeedbackSize, 0) | |
return $encCreateMethod.Invoke($CSP, $encParams) -as [System.Security.Cryptography.ICryptoTransform] | |
} | |
function Get-LMHash { | |
<# | |
.SYNOPSIS | |
Calculates a LAN Manager Hash from a password | |
.DESCRIPTION | |
Get-Help calculates a LAN Manager Hash from a password, useful for forensic research on Windows | |
.EXAMPLE | |
PS C:\> Get-LMHash password | |
Password LMHash | |
-------- ------ | |
PASSWORD e52cac67419a9a224a3b108f3fa6cb6d | |
In this example Get-LMHash outputs the lmhash corresponding to the password "password" | |
.INPUTS | |
String | |
.NOTES | |
The LAN Manager hash algorithm goes something like this: | |
1. Password is truncated to a length of 14 characters | |
2. Password characters are converted to upper case | |
3. Password is OEM encoded (CP 437 on most windows locales) | |
4. Encoded password is right-padded with 0-bytes up to a length of 14 | |
5. Password is split into two 7-byte strings | |
6. Each string is further: | |
6a. Split into 7-bit chunks (BE/MSB) | |
6b. Left-shifted 1 bit (ie. right-pad each 7-bit chunk with 0) | |
6c. Resulting 8-byte key is used to DES encrypt the magic plaintext message "KGS!@#$%" in ECB mode | |
7. Resulting cipher texts are concatenated to form the LM hash | |
#> | |
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "", Justification = "We're producing LM hashes here, security is obviously not of concern")] | |
param( | |
[Parameter(Mandatory = $true, ValueFromPipeline = $false)] | |
[AllowEmptyString()] | |
[string]$Password | |
) | |
# Define the magic plaintext constant | |
$MagicNumber = [System.Text.Encoding]::ASCII.GetBytes("KGS!@#$%") | |
# Convert password to upper case | |
$Password = $Password.ToUpper() | |
# Pad it with null-bytes up to length 14 | |
$Password = $Password.PadRight(14, 0) | |
# Split into two substrings of length 7, discard any input beyond length 14 | |
$FirstHalf, $SecondHalf, $null = $Password -split '(?<=\G.{7}(?<!$))' | |
try { | |
# Instantiate a DES csp | |
$DESProv = [System.Security.Cryptography.DESCryptoServiceProvider]::new() | |
$DESProv.Padding = 'None' | |
# Iterate over both halfs of the password | |
$LMHash = foreach ($half in $FirstHalf, $SecondHalf) { | |
# Convert string to byte array | |
$inBytes = [System.Text.Encoding]::GetEncoding(437).GetBytes($half) | |
# Create a binary string from our bytes | |
$bitString = '' | |
foreach ($byte in $inBytes) { | |
$bitstring += [convert]::ToString($byte, 2).PadLeft(8, '0') | |
} | |
# Partition the byte string into 7-bit chunks | |
[byte[]]$key = $bitString -split '(?<=\G.{7}(?<!$))' |ForEach-Object { | |
# Insert 0 as the least significant bit in each chunk | |
# Convert resulting string back to [byte] | |
[convert]::ToByte("${_}0", 2) | |
} | |
try { | |
# Create encryptor from our new key, and an empty IV | |
$enc = Get-WeakDESEncryptor -CSP $DESProv -Key $key | |
$enc.TransformFinalBlock($MagicNumber, 0, 8) | |
} | |
finally { | |
# Dispose of the encryptor | |
if ($enc) { | |
$enc.Dispose() | |
$enc = $null | |
} | |
} | |
} | |
} | |
finally { | |
# Disposed of the DES provider | |
if ($DESProv) { | |
$DESProv.Dispose() | |
} | |
} | |
return [PSCustomObject]@{ | |
Password = $Password | |
LMHash = [System.BitConverter]::ToString($LMHash).Replace('-', '').ToLower() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment