-
Notifications
You must be signed in to change notification settings - Fork 2
/
port-knocker.ps1
334 lines (288 loc) · 11.3 KB
/
port-knocker.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
<#
.SYNOPSIS
Lock/Unlock ports by knocking closed ports
.DESCRIPTION
Enable/Disable ports by sending a sequence of SYN packets
to pre-defined ports. The Knockd service checks the windows
firewall logs to see if SYN packets were sequentially sent
to the defined ports within a space of x (default = 10) seconds
from the same IP address and then, enable/disable a port.
.EXAMPLE
.\port-knocker.ps1
.LINK
https://github.com/Tomiwa-Ot/windows-port-knocker
#>
Function Clear-Screen {
param ()
Clear-Host
}
Function Write-Banner {
param ()
Write-Host "`t******* ** ** ** ** "
Write-Host "`t/**////** /** /** ** /** "
Write-Host "`t/** /** ****** ****** ****** /** ** ******* ****** ***** /** ** ***** ******"
Write-Host "`t/******* **////**//**//*///**/ /**** //**///** **////** **///**/** ** **///**//**//*"
Write-Host "`t/**//// /** /** /** / /** /**/** /** /**/** /**/** // /**** /******* /** / "
Write-Host "`t/** /** /** /** /** /**//** /** /**/** /**/** **/**/** /**//// /** "
Write-Host "`t/** //****** /*** //** /** //** *** /**//****** //***** /**//**//******/*** "
Write-Host "`t// ////// /// // // // /// // ////// ///// // // ////// /// "
Write-Host "`t by @Tomiwa-Ot"
Write-Host ""
Write-Host ""
}
Function Write-Menu {
param ()
Clear-Screen
Write-Banner
Write-Host "1: Start knocking service"
Write-Host "2: Stop knocking service"
Write-Host "3: Knockd service status"
Write-Host "4: Knock a port"
Write-Host "5: Disable knocking for a port"
Write-Host "6: List knocked ports"
Write-Host "7: Exit`n"
$choice = Read-Host -Prompt '> '
switch ($choice) {
1 { Start-KnockdService }
2 { Stop-KnockdService }
3 { Get-KnockdStatus }
4 { Enable-PortKnocking }
5 { Disable-PortKnocking }
6 { Get-KnockedPorts }
7 { Clear-Screen }
Default { Write-Menu }
}
}
Function Enable-PortKnocking {
param ()
Clear-Screen
Write-Banner
$port = Read-Host -Prompt 'Enter port to knock (1 - 65535) '
$protocol = Read-Host -Prompt 'Enter protocol (tcp/udp) '
$openSequence = (Read-Host -Prompt "Enter knock sequence for unlocking $port (use commas to seperate values)").Split(',') -replace " ", ""
$closeSequence = (Read-Host -Prompt "Enter knock sequence for locking $port (use commas to seperate values)").Split(',') -replace " ", ""
$output = Get-PortStatus -Port $port -Protocol $protocol
if ($null -ne $output.ErrorMessage) {
Write-Warning $output.ErrorMessage
Read-Host -Prompt 'Press any key to continue... '
Write-Menu
return
}
foreach ($value in $openSequence) {
if (!([int]$value -ge 1 -or [int]$value -le 65355)) {
Write-Warning 'Port cannot less than 1 and greater than 65535'
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
return
}
Get-NetTCPConnection -LocalPort $value -ErrorAction Ignore | Out-Null
if ($?) {
$service = (Get-Process -Id (Get-NetTCPConnection -LocalPort $value).OwningProcess).ProcessName
Write-Warning "Cannot use port $value in open sequence, $service is using it"
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
return
}
}
foreach ($value in $closeSequence) {
if (!([int]$value -ge 1 -or [int]$value -le 65355)) {
Write-Warning 'Port cannot less than 1 and greater than 65535'
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
return
}
Get-NetTCPConnection -LocalPort $value -ErrorAction Ignore | Out-Null
if ($?) {
$service = (Get-Process -Id (Get-NetTCPConnection -LocalPort $value).OwningProcess).ProcessName
Write-Warning "Cannot use port $value in close sequence, $service is using it"
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
return
}
}
$yes = [System.Management.Automation.Host.ChoiceDescription]::new('&Yes', 'Proceed to knock port')
$no = [System.Management.Automation.Host.ChoiceDescription]::new('&No', 'Stop process')
Write-Host "`nPort: $port/$protocol"
Write-Host "Service: $($output.ServiceName)"
Write-Host "Open Sequence: $openSequence"
Write-Host "Close Sequence: $closeSequence`n"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$result = $host.UI.PromptForChoice('', "Are you sure want to knock $($output.ServiceName) $Port/tcp?", $options, 0)
switch ($result) {
0 {
Write-Host ''
Write-Host 'Writing to cache ...'
Add-JsonCache -Service "$($output.ServiceName)" -Port $port -Protocol $protocol -OpenSequence $openSequence -CloseSequence $closeSequence
Write-Host "$port/$protocol knocked successfully`n"
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
}
1 { Write-Menu }
Default { Write-Menu }
}
}
Function Add-JsonCache {
param (
[Parameter(Mandatory)]
[string]$Service,
[Parameter(Mandatory)]
[int]$Port,
[Parameter(Mandatory)]
[string]$Protocol,
[Parameter(Mandatory)]
[array]$OpenSequence,
[Parameter(Mandatory)]
[array]$CloseSequence
)
$json = Get-Content '.\data.json' | ConvertFrom-Json
$data = "" | Select-Object Service, Port, Protocol, OpenSequence, CloseSequence
$data.Service = $Service
$data.Port = $Port
$data.Protocol = $Protocol
[array]$openSeq = foreach ($sequence in $OpenSequence) {
[int]::Parse($sequence)
}
$data.OpenSequence = $openSeq
[array]$closeSeq = foreach ($sequence in $CloseSequence) {
[int]::Parse($sequence)
}
$data.CloseSequence = $closeSeq
[array]$json.Daemon += $data
$json | ConvertTo-Json | Set-Content '.\data.json'
}
Function Disable-PortKnocking {
param ()
Clear-Screen
Write-Banner
$Port = Read-Host -Prompt 'Enter knocked port to disable '
$Protocol = Read-Host -Prompt 'Enter protocol (tcp/udp) '
$json = Get-Content '.\data.json' | ConvertFrom-Json
foreach ($object in $json.Daemon) {
if ($object.Port -eq $Port -and $object.Protocol -eq $Protocol) {
$yes = [System.Management.Automation.Host.ChoiceDescription]::new('&Yes', "Disable knocking on port $($object.Port)/$($object.Protocol) $($object.Service)")
$no = [System.Management.Automation.Host.ChoiceDescription]::new('&No', 'Cancel')
Write-Host ""
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$result = $host.UI.PromptForChoice('', "Are you sure disable knocking on $($object.Service) $Port/$($object.Protocol)?", $options, 0)
switch ($result) {
0 {
Write-Host 'Updating cache...'
[array]$json.Daemon = $json.Daemon | Where-Object { $_.Service -ne $object.Service }
$json | ConvertTo-Json | Set-Content '.\data.json'
Write-Host "Knocking on port $($object.Port)/$($object.Protocol) has been disabled"
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
return
}
1 { Write-Menu; return }
Default { Write-Menu; return }
}
}
}
Write-Warning "Port $Port/$Protocol is not knocked"
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
}
Function Get-KnockedPorts {
param ()
Clear-Screen
Write-Banner
$json = Get-Content '.\data.json' | ConvertFrom-Json
$json.Daemon | Select-Object Service, Port, Protocol, OpenSequence, CloseSequence | Format-Table | Out-Host
Read-Host -Prompt 'Press any key to continue... '
Write-Menu
}
Function Get-PortStatus {
param (
[int]$Port,
[string]$Protocol
)
$output = '' | Select-Object ServiceName, ErrorMessage
if (!($Port -ge 1 -or $Port -le 65355)) {
$output.ErrorMessage = 'Port cannot less than 1 and greater than 65535'
return $output
}
if ($Protocol.ToLower() -eq 'tcp') {
Get-NetTCPConnection -LocalPort $Port -ErrorAction Ignore | Out-Null
if ($?) {
$output.ServiceName = (Get-Process -Id (Get-NetTCPConnection -LocalPort $Port).OwningProcess).ProcessName
} else {
$output.ErrorMessage = "No service is running on $Port/tcp"
}
} elseif ($Protocol.ToLower() -eq 'udp') {
Get-NetUDPEndpoint -LocalPort $Port -ErrorAction Ignore | Out-Null
if ($?) {
$output.ServiceName = (Get-Process -Id (Get-NetUDPEndpoint -LocalPort $Port).OwningProcess).ProcessName
} else {
$output.ErrorMessage = "No service is running on $Port/udp"
}
} else {
$output.ErrorMessage = 'Invalid protocol'
}
return $output
}
Function Start-KnockdService {
param ()
Write-Host 'Starting windows firewall...'
Write-Host 'Enabling logging for blocked requests...'
Set-NetFirewallProfile -Enabled True -LogBlocked True
$service = Get-Service -ErrorAction Ignore | Where-Object -Property Name -eq Knockd
if ($null -ne $service) {
if ($service.Status -eq 'Stopped') {
Write-Host 'Starting Knockd service...'
Start-Service Knockd
if($?) {
Write-Host 'Knockd service started successfully'
} else {
Write-Warning 'Something went wrong. Knockd not started'
}
} else {
Write-Host 'Knockd is already running'
}
} else {
$params = @{
Name = 'Knockd'
BinaryPathName = "$($PSScriptRoot)\knockd.ps1"
DisplayName = 'Port Knocking Service'
StartupType = 'Automatic'
Description = 'Windows Port Knocking Service'
}
Write-Host 'Creating Knockd service'
New-Service @params
Write-Host 'Starting Knockd service...'
Start-Service Knockd
if($?) {
Write-Host 'Knockd service started successfully'
} else {
Write-Warning 'Something went wrong. Knockd not started'
}
}
Read-Host -Prompt "`nPress any key to continue..."
Write-Menu
}
Function Stop-KnockdService {
param ()
Clear-Screen
Write-Banner
Stop-Service Knockd -ErrorAction Ignore
if ($?) {
Write-Host 'Knockd service has been stopped'
} else {
Write-Warning 'Something went wrong'
}
Write-Host ''
Read-Host -Prompt 'Press any key to continue'
Write-Menu
}
Function Get-KnockdStatus {
param ()
Clear-Screen
Write-Banner
Get-Service Knockd -ErrorAction Ignore
if(!$?) {
Write-Warning "Knockd service doesn't exist"
}
Read-Host -Prompt 'Press any key to continue...'
Write-Menu
}
Write-Menu