Using PowerShell for Brute-Force Password Cracking (Example Script)
Can PowerShell be used as a penetration testing tool? The answer is yes. Here’s a script for a brute-force password cracker.
April 17, 2024
I recently used PowerShell to build an app for generating strong, random passwords based on selectable criteria. After writing my GUI-based password generator, I began to wonder about the possibility of using PowerShell to do the opposite – crack passwords.
As I pondered the idea, I contemplated which type of password I should try to crack, given the variety of different passwords available. Ultimately, I decided to try my luck with a password-protected file I had long been locked out of due to forgetting the password.
After extensive trial and error, I was indeed able to use PowerShell to crack the password for the aforementioned file. However, as I prepared to write this article about the experiment, I asked myself whether it would be irresponsible of me to publish a tool designed to defeat a password prompt. Ultimately, I decided to publish a modified version of my script. After all, a PowerShell brute-force password cracker could serve legitimate purposes in penetration testing. The modification that I made involved removing certain code segments from the script to limit its functionality.
This modified script could be thought of as a do-it-yourself penetration testing tool, providing the basic structure for brute-force password cracking. I have stopped short of publicly releasing a tool that can crack passwords without being modified.
PowerShell Script for Brute-Force Password Cracking
With that all said, here is my script:
Function Test-Password
{
Param(
[String]$Password
)
$ErrorOccurred = $False
Try{
# Insert the code here to attempt using the current password
}
Catch {
$ErrorOccurred = $True
Return $ErrorOccurred
}
Return $ErrorOccurred
}
$UpperCase = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
$LowerCase = @('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')
$Numbers = @('1','2','3','4','5','6','7','8','9','0')
$Symbols = @('!','@','$','?','<','>','*','&')
$Charset = @()
ForEach-Object {
$UpperCase | ForEach-Object {
$Charset += $_
}
$LowerCase | ForEach-Object {
$Charset += $_
}
$Numbers | ForEach-Object {
$Charset += $_
}
$Symbols | ForEach-Object {
$Charset += $_
}
}
$MaxDepth = 8
$combinations = @("")
for ($depth = 1; $depth -le $MaxDepth; $depth++) {
$newCombinations = @()
foreach ($combination in $combinations) {
foreach ($char in $Charset) {
$newCombination = $combination + $char
Write-Host $newCombination
$Password = $NewCombination
$ErrorOccurred = Test-Password -Password $Password
If ($ErrorOccurred -eq $False){
Write-Host "Password Found: " $Password
Exit
}
If ($ErrorOccurred -eq $True){
Write-Host "Password Not Found: " $Password
}
$newCombinations += $newCombination
}
}
$combinations = $newCombinations
}
How the PowerShell Script Works
Let’s look at how this script works.
1. The script body begins by defining several character sets, including $UpperCase, $LowerCase, $Numbers, and $Symbols. These sets determine the characters that will be used in password-guessing attempts. The lines of code are directly copied from my GUI password generator script but can be adjusted to include additional characters if necessary.
2. Following this, a block of code creates an array called $Charset. I add each character defined within $UpperCase, $LowerCase, $Numbers, and $Symbols to the $CharSet array. That way, a single array contains every possible character to be used in password-guessing attempts.
3. Next, a line of code sets $MaxDepth to 8. The $MaxDepth variable defines the maximum password length. For right now, with $MaxDepth set to 8, the script will attempt password guesses of up to 8 characters in length. You can change this number to adjust the maximum password length.
4. The subsequent lines of code use a For statement and a couple of ForEach statements to cycle through all possible passwords. The current password guess is stored in a variable called $NewCombination, while the $Password variable also stores the current password guess.
5. Just after the $Password variable is defined, you will notice a line:
$ErrorOccurred = Test-Password -Password $Password
This line of code passes the current password guess to a function called Test-Password. The function returns a variable called $ErrorOccurred, which will either be assigned a value of $True or $False.
The function itself is relatively simple. It initially sets $ErrorOccurred to $False. Incidentally, if you just want to see the script cycling through all possible password combinations on screen without actually cracking a password, you can change the initial value of $ErrorOccurred to $True. You can see what the script does after such a modification in Figure 1.
Figure 1. This is what happens if you change $False to $True.
6. Once $ErrorOccurred is set, you will notice a Try statement. This is where you would insert the code to attempt submitting the current password guess to see if it is valid. The approach here is that if the password guess fails (because the password is incorrect), PowerShell will return an error. This triggers the Catch section to execute, setting $ErrorOccurred to $True before returning to the script’s main body. Otherwise, if no error occurs, the password is presumed correct, leaving $ErrorOccurred as $False.
Before moving forward, I will give you one more hint about making this script work as an actual brute-force cracking tool. To make the script work as intended, I had to append -ErrorAction Stop to the end of the line of code that submits the password guess to the file I aimed to crack. This addition ensures that the code within the Catch section is executing.
7. Once PowerShell returns to the script’s main body, there is a simple check to see if $ErrorOccurred is set to $True or $False. If $ErrorOccurred is true, the current password guess was rejected, meaning that the password is incorrect. Conversely, if ErrorOccurred is false, the password was accepted, meaning that the password is correct. At that point, the script should display the new password and terminate.
It is worth noting that when I actually used this script to crack a password, the Exit command did not terminate the script. That meant that I had to remove the “Password Not Found” line just so that I could see which password was ultimately accepted. However, I believe that this anomaly had more to do with the type of password being cracked and the approach taken, rather than an issue with the script itself.
About the Author
You May Also Like