Created
August 5, 2019 23:04
-
-
Save drsox/4a68420563179294fa960b83fed17438 to your computer and use it in GitHub Desktop.
Server 2019 Block-FailedRDPAttempts.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Revision: 20190806-0001 | |
Original script from: | |
https://gist.github.com/drsox/d7048edf847773af31b9e24d406a822b | |
==Notes== | |
If you use a non-standard RDP port make sure you edit the "Block-FailedRDPAttempts.ps1" file | |
to change 3389 to the RDP port that you do use. | |
==INSTALL== | |
Copy the two ps1 files to a temporary folder (they can be deleted later). | |
Open Powershell as elevated / Administrator. | |
cd to the folder (e.g. cd c:\temp\) | |
type Deploy-RDPBruteForceBlocker.ps1 and press enter. | |
this will copy the "Block-FailedRDPAttempts.ps1" file to c:\program files\windowspowershell\scripts | |
and add a scheduled task to run the script. It also runs the script once. | |
Once installed you should go into scheduled tasks and set the task to "Run whether the user is logged on or not" and supply an administrator account. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Only compatible with Server 2019 | |
# Intended to be run as a recurring scheduled task | |
# Parses 240 minutes of logs then based on a tolerance for failed login attempts, creates TCP 3389 (RDP) and ICMP block rules. | |
# This will remove the old rules each time it is run which has the effect of creating a temporary block if this is run as a scheduled task. | |
#Quantity of failed login attempts required to trigger blocking | |
$tolerance = 15 | |
$logName = "Security" | |
#Increase log retention to have enough logs to work with | |
if((Get-WinEvent -ListLog $logName).MaximumSizeInBytes -lt 20000000){ | |
$log = New-Object System.Diagnostics.Eventing.Reader.EventLogConfiguration $logName | |
$log.MaximumSizeInBytes=20000000 | |
$log.SaveChanges() | |
} | |
#Filter logs for desired event | |
$events = Get-WinEvent -ea 0 -FilterHashtable @{LogName="Security"; ID=4625; StartTime = ((get-date).AddMinutes(-240))} | |
#IP Address Regex | |
$regex = [regex] "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" | |
$list = @() | |
#Pull lines with IP addresses out of events object | |
foreach($message in $events.Message){ | |
$list += (Select-String -InputObject $message -Pattern $regex).Matches.Value | |
} | |
#Group objects so that occurances can be counted | |
$group = $list | Group-Object | |
$blackList = @() | |
#Add Addresses with sufficient occurances to blacklist | |
foreach($entry in $group){ | |
if($entry.Count -ge $tolerance){ | |
$blackList += $entry.Name | |
} | |
} | |
#Clear prior entries from Windows Firewall and implement new entries based on black list | |
Get-NetFirewallRule -Name "RDP_BlackList_RDP" | Remove-NetFirewallRule -ErrorAction SilentlyContinue | |
Get-NetFirewallRule -Name "RDP_BlackList_ICMP" | Remove-NetFirewallRule -ErrorAction SilentlyContinue | |
if ($blackList.count -ne 0) { | |
write-host "Entries are in block array, will apply a block." | |
New-NetFirewallRule -Name "RDP_BlackList_RDP" -DisplayName "RDP_BlackList_RDP" -Direction Inbound -LocalPort 3389 -Protocol TCP -Action Block -RemoteAddress $blackList | |
New-NetFirewallRule -Name "RDP_BlackList_ICMP" -DisplayName "RDP_BlackList_ICMP" -Direction Inbound -Protocol ICMPv4 -Action Block -RemoteAddress $blackList | |
} else { | |
write-host "No entries in block array, will not apply a block." | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Deploys Block-FailedRDPAttempts.ps1 as a scheduled task in a consistent and repeatable way | |
param( | |
[Parameter(Mandatory=$false)][string]$taskName = "RDPBruteForceBlocker", | |
[Parameter(Mandatory=$false)][string]$scriptDirectory = 'C:\Program Files\WindowsPowerShell\Scripts\', | |
[Parameter(Mandatory=$false)][string]$scriptName = 'Block-FailedRDPAttempts.ps1', | |
#[Parameter(Mandatory=$false)][SecureString] $creds = (Get-Credential), | |
[Parameter(Mandatory=$false)]$repeat = (New-TimeSpan -Minutes 60) | |
) | |
$ErrorActionPreference = "Stop" | |
#Create event log source if it doesn't exist | |
if([System.Diagnostics.EventLog]::SourceExists("RDPBruteForceBlocker") -eq $False){ | |
New-EventLog -LogName "RDPBruteForceBlocker" -Source "RDPBruteForceBlocker" | |
} | |
# Create directory if it doesn't exist | |
if(!(Test-Path $scriptDirectory)){ | |
New-Item -ItemType Directory -Path $scriptDirectory | |
} | |
# Deploy scripts | |
Copy-Item (".\" + $scriptName) -Destination $scriptDirectory -Force | |
#Deploy Schedule Task | |
$action = New-ScheduledTaskAction -Execute 'powershell.exe' ` | |
-Argument ('-executionpolicy bypass -NoProfile -file "' + $scriptDirectory + $scriptName + '"') | |
#Set trigger to repeat on interval | |
$dt= ([DateTime]::Now) | |
$duration = $dt.AddYears(25) -$dt; | |
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).Date -RepetitionInterval $repeat -RepetitionDuration $duration | |
#Remove existing task to avoid conflict | |
Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue | |
#Register scheduled task | |
Register-ScheduledTask ` | |
-Action $action ` | |
-Trigger $trigger ` | |
-TaskName $taskName ` | |
-Description $taskName ` | |
-RunLevel Highest | |
#Run To Validate | |
Get-ScheduledTask -TaskName $taskName | Start-ScheduledTask | |
do{ | |
$taskInfo = Get-ScheduledTaskInfo -TaskName $taskName | |
Start-Sleep 3 | |
} while ($taskInfo.LastTaskResult -eq 267009) | |
if($taskInfo.LastTaskResult -eq 0){ | |
Write-EventLog -LogName "RDPBruteForceBlocker" -Source "RDPBruteForceBlocker" -EventId 1010 -EntryType SuccessAudit -Message "Scheduled task deployment succeeded for: $taskName" | |
}else{ | |
Write-EventLog -LogName "RDPBruteForceBlocker" -Source "RDPBruteForceBlocker" -EventId 1011 -EntryType Error -Message "Scheduled task deployment failed for: $taskName" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment