Identifying Compromised Passwords (Part 1)

by May 14, 2020

Passwords are no longer considered safe when they are complex. Instead, you need to ensure that passwords have not been compromised and are not part of default attacker dictionaries. Even the most complex password is unsafe if it is routinely checked by automated attacks.

To find out whether a password is compromised, use the function below:

function Test-Password
{
  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory, Position=0)]
    [System.Security.SecureString]
    $Password
  )
  
  # take securestring and get the entered plain text password
  # we are using a securestring only to get a masked input box
  $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
  $plain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    
  # hash the password
  $bytes = [Text.Encoding]::UTF8.GetBytes($plain)
  $stream = [IO.MemoryStream]::new($bytes)
  $hash = Get-FileHash -Algorithm 'SHA1' -InputStream $stream
  $stream.Close()
  $stream.Dispose()
  
  # separate the first 5 hash characters from the rest
  $first5hashChars,$remainingHashChars = $hash.Hash -split '(?<=^.{5})'
  
  # send the first 5 hash characters to the web service
  $url = "https://api.pwnedpasswords.com/range/$first5hashChars"
  [Net.ServicePointManager]::SecurityProtocol = 'Tls12'
  $response = Invoke-RestMethod -Uri $url -UseBasicParsing
  
  # split result into individual lines...
  $lines = $response -split '\r\n'
  # ...and get the line where the returned hash matches your
  # remainder of the hash that you kept private
  $filteredLines = $lines -like "$remainingHashChars*"
  
  # return the number of compromises
  [int]($filteredLines -split ':')[-1]
}

It’s very simple to use: simply provide your password to the function Test-Password. It returns the number of known compromises, and any password returning more than 0 compromises is considered unsafe and must be changed.

 
PS> $password = Read-Host -AsSecureString

PS> Test-Password -Password $password
4880 
 

The password must be submitted as a SecureString. You can either run Test-Password without a password in which case you get safely prompted. Or you need to read the password as a SecureString.

In the example, the complex password “P@$$w0rd” surfaced in 4880 attacks and is completely unsafe to use.

If you’d like to add more information, i.e. whether software is 32- or 64-bit, or if you’d like to turn the code into a reusable new PowerShell command, there is more reading for you here: https://powershell.one/code/5.html.


Twitter This Tip! ReTweet this Tip!