Skip to content

Instantly share code, notes, and snippets.

@mrik23
Last active August 3, 2022 20:28
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mrik23/e8efe6dc9cdfe62c9d0bb84dc25288fa to your computer and use it in GitHub Desktop.
Save mrik23/e8efe6dc9cdfe62c9d0bb84dc25288fa to your computer and use it in GitHub Desktop.
PowerShell script to check password against leaked password database from https://haveibeenpwned.com/ using the Pwned Passwords V2 API. Only the first 5 characters of the password string hash is checked against the API (k-anonymity). More info on the HIBP API at https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/.
#requires -version 4
<#
.SYNOPSIS
Check password against leaked password database from https://haveibeenpwned.com/ using the Pwned Passwords V2 API https://api.pwnedpasswords.com/range/<hashPrefix>.
.DESCRIPTION
Only the first 5 characters of the password string hash is checked against the API (k-anonymity). The API returns a list of all passwords matching the hash prefix, then the script checks if the suffix is present or not.
More info on the HIBP API at https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/.
.PARAMETER Password
Enter the password to check.
.PARAMETER SecurePassword
Switch to enable secure prompt for password.
.EXAMPLE
.\Test-LeakedPasswordHIBP.ps1 -password "P@ssw0rd"
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[string]$Password,
[Parameter(Mandatory=$False)]
[switch]$SecurePassword
)
if ($SecurePassword) {
$Credentials = Get-Credential -Message "Enter the password to test" -UserName "dummy"
$Password = $credentials.GetNetworkCredential().Password
} else {
if ($Password -eq "") {
$Password = Read-Host -Prompt "Enter the password to test"
}
}
#Force TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
#Create SHA-1 hash from string
Function Get-StringHash()
{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$True)]
[String]$inputString
)
$Private:outputHash = [string]::Empty
$hasher = New-Object -TypeName "System.Security.Cryptography.SHA1CryptoServiceProvider"
$hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($inputString)) | ForEach-Object { $outputHash += $_.ToString("x2") }
$outputHash.ToUpper()
}
$stringHash = Get-StringHash -inputString $Password
$hashPrefix = $stringHash.Substring(0, 5)
$hashSuffix = $stringHash.Substring(5, ($stringHash.Length - 5))
try {
$response = Invoke-RestMethod -Uri "https://api.pwnedpasswords.com/range/$($hashPrefix)" -Method Get -ErrorVariable errorRequest
}
catch {
Write-Output "Error with the request!"
Write-Output $errorRequest
break
}
if ($response -ne $null) {
$findHashSuffix = $response.Contains($hashSuffix)
if ($findHashSuffix -eq $true) {
$result = $response.Substring($response.IndexOf($hashSuffix), $response.IndexOf([System.Environment]::NewLine, $response.IndexOf($hashSuffix)) - $response.IndexOf($hashSuffix))
$resultCount = ($result.Split(":"))[1]
Write-Output "Your password has been found $($resultCount) times!"
}
else {
Write-Output "Your password has not been found."
}
}
else {
Write-Output "No occurence of the hash prefix found."
}
@stvflowers
Copy link

It should be noted that haveibeenpwned.com strongly discourages you from testing production or sensitive passwords in this way.

@pyrocumulus
Copy link

@toledotown I don't think that's entirely correct. They discourage you from using the passwords page on the HIBP website and entering passwords you actually use on that site. What this script does is hash the password on the client machine and only send the first five characters to the HIBP api for verification.

But, one could say that using a script like this poses a risk in itself. Which is quite true, but only when you don't understand the script.

@mrik23
Copy link
Author

mrik23 commented Mar 2, 2018

As long as you trust the machine on which the script is running, I think it's pretty safe. We just retrieve a list of hash from the API and then the comparison is done locally on the machine.

@patschi
Copy link

patschi commented May 8, 2019

If anyone comes across the same issue: The script unfortunately fails on non-Windows machines, e.g. using PSCore on Linux. The failing line is 92, and related to the Substring.

The reason is that [System.Environment]::NewLine returns back following:

  • on Windows: \r\n
  • on Linux: \n

But as the HIBP API reports back the hashes splitted by the Windows line-endings, the IndexOf/Substring at line 92 fails. The fix is quite simple: Just replace [System.Environment]::NewLine on line 92 with `r`n.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment