Skip to content

Instantly share code, notes, and snippets.

@IISResetMe
Last active March 15, 2019 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IISResetMe/50376918042912fecc5ff1402e1b7dbe to your computer and use it in GitHub Desktop.
Save IISResetMe/50376918042912fecc5ff1402e1b7dbe to your computer and use it in GitHub Desktop.
LMHash generator in written in PowerShell
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