PowerShell + Windows Firewall: RDP Brute Force Protection - UPDATE

If you have a server on the internet you will probably already be aware that there are scumbags out there running apps that just scan every IP on common ports like SSH or RDP. When they find an IP that gives a response they set up shop trying to brute force you. If you have a strong password the risk is minimal but it is annoying. It fills up your event viewer with crap and hell, they might actually get lucky and get in.

Windows firewall is a really good tool but unless you are going to be manually adding these IP's to ban rule everyday its not doing you much good. What you need is for the firewall to automatically add offending IP's to the rules...

Schedule this script to run once a and will permanently block any IP that makes more than 50 failed login attempts to your server in the life of your event log.

$ips = $null

$BadLogins = GET-EVENTLOG -Logname Security | where { $_.EntryType -eq 'FailureAudit' } | select -ExpandProperty message 

Foreach ($BadLogin in $BadLogins)

{
$ip = [regex]::Matches($BadLogin,"\b(?:\d{1,3}\.){3}\d{1,3}\b") 
$ips += $ip
}

$VeryBadIPs = $ips.value | Group-Object -noelement | where {$_.count -gt 50}

# $ExsistiengBadips = (Get-NetFirewallRule -DisplayName "Very_Bad_ips" | Get-NetFirewallAddressFilter ).RemoteAddress

$VeryBadIPs = $VeryBadIPs.name + $ExsistiengBadips

$VeryBadIPs =  $VeryBadIPs | sort -Unique

set-netfirewallrule -RemoteAddress $VeryBadIPs -displayname "Very_Bad_ips" -direction inbound -action Block

Some people are nuts when it comes to rate limits!
If you have a strong password policy it will take a hacker hundreds of thousands, if not millions of attempts to hack a password. This great website will give you some idea of the time scales.

https://howsecureismypassword.net/

This assumes that the hacker is using the full power at there disposal, that your machine is able to respond to the login attempts quick enough, and you don't notice the sudden rise in load.

In the wild I often see very unwise application of rate limits. 3 attempts then account locked is very common in enterprise estates. This is only going to protect the system from is its intended users. 100 attempts an hour would make it incredibly difficult for a user to lock themselves out and make brute force attacks pretty much useless.

UPDTE

I recently tried to apply this to a windows 2012R2 server only to find that the event failure audit did not actually contain the IP address of the log in attempt making my script useless.

Lucky the ip is still logged somewhere else in an application log. So here is the version for server 2012R2 and probably windows versions before that (although I havent tested them.)

$ips = $null

$BadLogins = Get-WinEvent -LogName Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational  | where { $_.id  -eq '140' } | select -ExpandProperty message 

Foreach ($BadLogin in $BadLogins)

{
$ip = [regex]::Matches($BadLogin,"\b(?:\d{1,3}\.){3}\d{1,3}\b") 
$ips += $ip
}

$VeryBadIPs = $ips.value | Group-Object -noelement | where {$_.count -gt 25}

$ExsistiengBadips = (Get-NetFirewallRule -DisplayName "Very_Bad_ips" | Get-NetFirewallAddressFilter ).RemoteAddress

$VeryBadIPs = $VeryBadIPs.name + $ExsistiengBadips

$VeryBadIPs =  $VeryBadIPs | sort -Unique

set-netfirewallrule -RemoteAddress $VeryBadIPs -displayname "Very_Bad_ips" -direction inbound -action Block