-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathProtect-RDSFromBruteforce.ps1
141 lines (121 loc) · 5.06 KB
/
Protect-RDSFromBruteforce.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
<#
.SYNOPSIS
Get failed logins through RDP from Eventlog and add firewall rule to block offending IPs
.DESCRIPTION
He protec
He attac
But most important
He put a block rule against brute-force attac
.INPUTS
None
.OUTPUTS
None
.EXAMPLE
.\ProtectFrom-RDPBruteForce.ps1
Call it from PS commandline
.EXAMPLE
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -file 'C:\Shares\Scripts\Protect-RDSFromBruteforce\Protect-RDSFromBruteforce.ps1' -FailedLoginCount 10
Call this script from Task Scheduler with FailedLoginCount set to 10 attempts
#>
param (
#How deep to look in the log, in minutes. Should be reasonably low, to avoid performance impact.
[int]$timePeriod = 60,
#How many failed logon attempts should be found for a single IP address to be added to the list of offending IPs
[int]$FailedLoginCount = 5,
#Time period, in minutes, after which block rule will be removed
[int]$RemoveBlockRuleAfter = 480,
#Full path for HTML report file. Report is generated only if path is given.
[string]$HTMLReportPath
)
$xpath = @"
<QueryList>
<Query Id="0" Path="Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational">
<Select Path="Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational">*[System[(Level=3) and (EventID=140) and TimeCreated[timediff(@SystemTime) <= $($timePeriod * 60 * 1000)]]]</Select>
</Query>
</QueryList>
"@
$Events= Get-WinEvent -Listlog Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational | Get-WinEvent -FilterXPath $xpath | select TimeCreated, MachineName, @{N="IP";E={$_.Properties.Value}}
if ($Events) {
$UniqueIPs = $events | select IP -Unique
$OffendingIPs = `
foreach ($UniqueIP in $UniqueIPs) {
$filteredEvents = @($events | ? {$_.ip -eq $UniqueIP.ip} | Sort-Object -Descending -Property TimeCreated)
if ($filteredEvents.count -ge $FailedLoginCount) {
$obj = '' | select `
@{N='IP';E={
$UniqueIP.IP}},
@{N='Attempts';E={
$filteredEvents.count}},
@{N='MinutesBetween';E={
$TimeDiff = $filteredEvents[0].TimeCreated - ($filteredEvents[$filteredEvents.count - 1].TimeCreated)
[math]::Round($TimeDiff.TotalMinutes,0)}},
@{N='LastAttemptAt';E={
$filteredEvents[0].TimeCreated}},
@{N='FirstAttemptAt';E={
$filteredEvents[$filteredEvents.count - 1].TimeCreated}}
$obj
}#end if
}#end foreach
}#end if events
#Get FW rules for blocking IPs
$dtNow = [datetime]::UtcNow | get-date -Format o | get-date
$NetFWRules = @(Get-NetFirewallRule -DisplayName "RDP-BruteForce-Block" ) | select `
@{N="DateAdded";E={
get-date $_.Description }},
@{N="IP";E={
($_ | Get-NetFirewallAddressFilter).RemoteAddress }},
@{N="TimeSpan";E={
[math]::Round(( ($dtNow ) - ($_.Description | get-date )).TotalMinutes,0) }},
@{N="Guid";E={$_.Name}},
@{N="Deleted";E={
if ([math]::Round(( ($dtNow ) - ($_.Description | get-date )).TotalMinutes,0) -ge $RemoveBlockRuleAfter) {
$True
}
else {
$False
}
}}
if ($OffendingIPs) {
#Generate FW rules
foreach ($OffendingIP in $OffendingIPs) {
$Splat = @{
DisplayName = "RDP-BruteForce-Block"
Description = [string]([datetime]::UtcNow | Get-Date -Format o)
RemoteAddress = $OffendingIP.IP
}
if ($NetFWRules | ? {$_.IP -eq $OffendingIP.ip}) {
"IP " + $OffendingIP.IP +" already in block list" | Write-Host
}
else {
$NewRule = New-NetFirewallRule @Splat `
-Action Block -Direction Inbound -Enabled True -Profile Any
}
}#end foreach
}#end offendingIPs
#Remove FW rules;
$NetFWRules | ? {$_.deleted} | % { Remove-NetFirewallRule -Name $_.Guid }
#Generate HTML Report
if ($HTMLReportPath) {
$HTMLBody = "* Generated at " + (get-date) + "<br>"
$HTMLBody += "* Time period is " + ($timePeriod * 60 ) + " seconds<br>"
$HTMLBody += "* Current bad login count cutoff: " + $FailedLoginCount + "<br>"
$HTMLBody += "* Current timeout for FW rule removal (minutes): " + $RemoveBlockRuleAfter + "<br>"
if ($OffendingIPs) {
$HTMLBody += "<hr><br>Current offending IPs:<br>"
$HTMLBody += $OffendingIPs | ConvertTo-Html -Fragment
}
else {
$HTMLBody += "<hr><br>There is no offending IPs in log<br>"
}
if ($NetFWRules) {
$HTMLBody += "<hr><br>Local firewall rules block list:<br>"
$HTMLBody += $NetFWRules | ConvertTo-Html -Fragment
}
else {
$HTMLBody += "<hr><br>No local firewall rules block list<br>"
}
if ( -not (Test-Path (Split-Path $HTMLReportPath) -ErrorAction SilentlyContinue) ) {
New-Item -ItemType Folder (Split-Path $HTMLReportPath)
}
ConvertTo-Html -Body $HTMLBody -Title "RDP-BruteForce-Block" | Set-Content -Path $HTMLReportPath
}#end HTML