Skip to content

Instantly share code, notes, and snippets.

@drsox
Created August 5, 2019 23:04
Show Gist options
  • Save drsox/4a68420563179294fa960b83fed17438 to your computer and use it in GitHub Desktop.
Save drsox/4a68420563179294fa960b83fed17438 to your computer and use it in GitHub Desktop.
Server 2019 Block-FailedRDPAttempts.ps1
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.
# 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."
}
# 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