From 247d26d492ca433ab9d82b8ad4480e79a9ae5c14 Mon Sep 17 00:00:00 2001 From: Tyler Hale Date: Mon, 13 Sep 2021 13:43:33 -0600 Subject: [PATCH] Initial commit --- Invoke-PortKnock.ps1 | 101 +++++++++++++++++++++++++++++++++++++++++++ README.md | 56 +++++++++++++++++++++--- 2 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 Invoke-PortKnock.ps1 diff --git a/Invoke-PortKnock.ps1 b/Invoke-PortKnock.ps1 new file mode 100644 index 0000000..912a5ec --- /dev/null +++ b/Invoke-PortKnock.ps1 @@ -0,0 +1,101 @@ +<# + +.SYNOPSIS +PowerShell script that knocks on a given sets of ports. It can optionally take an execute parameter to run a secondary script after the knocking is complete. + +.DESCRIPTION +PowerShell script that knocks on a given sets of ports. It can optionally take an execute parameter to run a secondary script after the knocking is complete. + +.PARAMETER Knock_Ports +Object Array for of the sequence of ports that should be knocked. The array must follow the following pattern. + +Destination, Port, Protocol + +.PARAMETER Delay +The time to pause between knocks in milliseconds. Defaults to 200 milliseconds. + +.PARAMETER Execute +Optional command that will be run after the knocking sequence is complete. This is passed directly to a Invoke-Expression command. + +.EXAMPLE +$Knock_Ports = @( + ("10.1.1.1", 36041, "TCP"), + ("10.1.1.1", 38097, "UDP"), + ("10.1.1.1", 27079, "TCP") +) + +PortKnock.ps1 -Knock_Ports $Knock_Ports + +.NOTES + Version: 1.0 + Author: Tyler Hale + Creation Date: 2021.09.13 + +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true)] + [Object[]] + $Knock_Ports, + [Parameter(Mandatory = $false)] + [int] + $Delay = 200, + [Parameter(Mandatory = $false)] + [string] + $Execute +) + +$ErrorDetected = $False + +foreach ($Knock in $Knock_Ports) { + if (!([ipaddress]::TryParse("$($Knock[0])",[ref][ipaddress]::Loopback))) { + $DNS_Resolve = (Resolve-DnsName $Knock[0]) + $Knock_Destination = $DNS_Resolve.IP4Address + } + else { + $Knock_Destination = $Knock[0] + } + + $Knock_Port = $Knock[1] + $Knock_Protocol = $Knock[2] + + try { + switch ($Knock_Protocol) { + "TCP" { + $tcpClient = New-Object System.Net.Sockets.TcpClient + $tcpClient.BeginConnect($Knock_Destination, $Knock_Port, $null, $null) | Out-Null + $tcpClient.Close() | Out-Null + } + "UDP" { + $udpClient = New-Object System.Net.Sockets.UdpClient + $udpClient.Connect($Knock_Destination, $Knock_Port) | Out-Null + $udpClient.Send([byte[]](0), 1) | Out-Null + $udpClient.Close() | Out-Null + } + default { + throw "Protocol not found $Knock_Protocol" + } + } + + Write-Verbose "Sent $Knock_Protocol packet to $($Knock_Destination):$Knock_Port" + } + catch { + Write-Error $_ + $ErrorDetected = $True + } + + Start-Sleep -Milliseconds $Delay +} + +if ($ErrorDetected) { + Write-Warning "Knock may not have completed successfully" +} +else { + Write-Host "Knock Complete" + + if ($null,"" -ne $Execute) { + Write-Verbose "Invoking command: $Execute" + Invoke-Expression -Command $Execute + } +} diff --git a/README.md b/README.md index 475ea7e..6ad7779 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,64 @@ PowerShell script that knocks on a given sets of ports. It can optionally take an execute parameter to run a secondary script after the knocking is complete. +It should be noted that using port knocking is not a security measure alone, it is generally used to minimize detections from random bots on the internet. It is easy to figure out a port knocking sequence so make sure that your systems are using security best practices. + ## Requirements ## Variables -| Variable | Required | Default | Choices | Description | -| -------- | -------- | ------- | ------- | ----------- | -| | | | | | +| Variable | Required | Default | Choices | Description | +| ----------- | -------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| Knock_Ports | Yes | | | Object Array for of the sequence of ports that should be knocked - The array must follow the following pattern | +| Delay | No | 200 | | The time to pause between knocks in milliseconds | +| Execute | No | | | Optional command that will be run after the knocking sequence is complete. This is passed directly to a Invoke-Expression command | + +### Knock_Ports Object + +| Variable | Required | Default | Choices | Description | +| ----------- | -------- | ------- | ------- | -------------------------------------- | +| Destination | Yes | | | Destination for port knock | +| Port | Yes | | | Port to be used for port knock | +| Protocol | Yes | | TCP,UDP | Protocol to be used for the port knock | ## Example +Simple port knock with a delay of 500ms to avoid issues on a high latency connection + +```powershell +$Knock_Ports = @( + ("10.1.1.1", 36041, "TCP"), + ("10.1.1.1", 38097, "UDP"), + ("10.1.1.1", 27079, "TCP") +) + +.\PortKnock.ps1 -Knock_Ports $Knock_Ports -Delay 500 +``` + +Port knock that initiates a RDP connection to a device after the knocking sequence is complete. + +```powershell +$Knock_Ports = @( + ("10.1.1.1", 36041, "TCP"), + ("10.1.1.1", 38097, "UDP"), + ("10.1.1.1", 27079, "TCP") +) + +.\PortKnock.ps1 -Knock_Ports $Knock_Ports -Execute "mstsc.exe /v:10.1.1.1:3389 /public" +``` + +Port knock that initiates a SSH connection to a device after the knocking sequence is complete. + +```powershell +$Knock_Ports = @( + ("10.1.1.1", 36041, "TCP"), + ("10.1.1.1", 38097, "UDP"), + ("10.1.1.1", 27079, "TCP") +) + +.\PortKnock.ps1 -Knock_Ports $Knock_Ports -Execute "ssh example@10.1.1.1" +``` + ## License See LICENSE file for full license information. - -## Screenshots