I was looking for a tool to block IP addresses after a certain number of failed RDP login attempts, something like fail2ban but for Windows. I came across IPBan. Calling IPBan a “fail2ban for Windows” unfairly minimizes what it can do, but it can handle that task quite nicely.
As a test I installed it on a Windows 2019 Server running in Azure using the provided install instructions from the README:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/DigitalRuby/IPBan/master/IPBanCore/Windows/Scripts/install_latest.ps1'))
You don’t want to blindly run a script that downloads and installs something on your machine without looking at it first, do you? Of course not. You take a look at the code first:
https://github.com/DigitalRuby/IPBan/blob/master/IPBanCore/Windows/Scripts/install_latest.ps1
Essentially, the script does the following:
- Downloads a zip file
- Extracts the files
- Sets up a Windows service
- Suggests that you might want to edit the config by opening the config file in Notepad
I took a look at the config file and made only one change to get started: I added a CenturyLink subnet to the allow list. CenturyLink is my ISP, and I didn’t want to accidentally lock myself out. Normally you wouldn’t want to add an entire /12 of your residential ISP, but this was just a test on a temporary and disposable server:
<add key="Whitelist" value="75.160.0.0/12"/>
I noted a few other interesting things in the config file:
- It can also examine Linux logs (IPBan can run on Windows or Linux)
- It blocks failed RDP logins, but also blocks failed logins for other Windows services, such as MSSQL and Exchange
- It defaults to banning an IP address after 5 failed attempts, but the number of failed attempts can be configured
- The default ban duration is 1 day, but this can be configured
- The default ban duration can take into account recidivism, so that the second or third time an address is banned it can use a longer duration
- It can also use a username-based allow list (whitelist), so that attempted logins from usernames not on the list will ban the IP address immediately
- It can add blocks based on external threat intelligence feeds, and uses the Emerging Threats blocklist by default
- It can pull the config file from a URL, allowing you to manage the configuration of many servers from one location.
After I reviewed the config file (C:\Program Files\IPBan\ipban.config
) I restarted the IPBAN service via Services GUI. You could also restart it via Powershell:
sc.exe stop IPBAN
sc.exe start IPBAN
Now that it was up-and-running, what changes did it make? I opened up Windows Defender Firewall and opened the Advanced Settings. Looking though the Inbound rules I found 4 rules prefixed with IPBAN_
, three Deny rules and one Allow rule:
- [Deny]
IPBan_Block_0
- [Deny]
IPBan_EmergingThreats_0
- [Deny]
IPBan_EmergingThreats_1000
- [Allow]
IPBan_GlobalWhitelist_0
I looked at the properties for IPBan_Block_0
. Already, one IP address had been banned! (I checked several hours later and only 2 additional IP addresses had been banned, so I may have gotten lucky to see one within minutes.)
It took me a while to figure out what the difference between IPBan_EmergingThreats_0
and IPBan_EmergingThreats_1000
. IPBan is creating a new firewall rule after 999 entries, so the 1000th IP address or subnet from the Emerging Threats feed was added to IPBan_EmergingThreats_1000
. I’ve seen some arguments online about whether or not there is a limit to the number of addresses or subnets that can be included in the scope for a Windows Defender Firewall rule, and some sources indicate there is a limit of 1000 (and I’m fairly certain the author of IPBan is one of the people arguing there is a limit).
The IPBan_GlobalWhitelist_0
contained the CenturyLink subnet that I explicitly allowed.
I was excited about pulling the configuration from a URL, so I added my configuration to https://osric.com/chris/ipban/ipban.example.config, initially with just one tweak:
<add key="UserNameWhitelist" value="chris"/>
This would, in theory, ban any IP address immediately if they used an address like admin or guest. It uses a configurable Levenshtein distance to try to avoid banning an IP address based on a typo (for example, chros instead of chris), which is a clever approach.
I then added the URL to the config file on the server itself:
<add key="GetUrlConfig" value="https://osric.com/chris/ipban/ipban.example.config"/>
After another service restart, I wanted to test to see if a login attempt with a bad username would cause an immediate block. I opened an RDP connection using the credentials admin:admin
and from a VPN IP address that would be outside of the allowed CenturyLink subnet.
I did not immediately see the VPN IP address in the IPBAN_Block_0
deny rule. I checked the logs (C:\Program Files\IPBan\logfile.txt
):
2021-12-31 04:35:45.3336|INFO|DigitalRuby.IPBanCore.Logger|Firewall entries updated:
2021-12-31 04:37:45.5791|WARN|DigitalRuby.IPBanCore.Logger|Login failure: 198.51.100.101, admin, RDP, 1
2021-12-31 04:37:45.5791|INFO|DigitalRuby.IPBanCore.Logger|IP blacklisted: False, user name blacklisted: False, fails user name white list regex: False, user name edit distance blacklisted: True
2021-12-31 04:37:45.5791|WARN|DigitalRuby.IPBanCore.Logger|Banning ip address: 198.51.100.101, user name: admin, config black listed: True, count: 1, extra info: , duration: 1.00:00:00
2021-12-31 04:37:45.6024|WARN|DigitalRuby.IPBanCore.Logger|Updating firewall with 1 entries...
2021-12-31 04:37:45.6024|INFO|DigitalRuby.IPBanCore.Logger|Firewall entries updated: 198.51.100.101
There was just a delay in adding it. I checked the IPBan_Block_0
deny rule again in Windows Defender Firewall and the IP address was there. I must have been exceedingly quick, as the cycle time defaults to 15 seconds:
<add key="CycleTime" value="00:00:00:15"/>
One other change I made to my config: I set this option to false so that any future tests would not send my VPN IP to the “global ipban database”:
<add key="UseDefaultBannedIPAddressHandler" value="true" />
Normally leaving that set to true should be fine, but during testing it would be good to avoid adding your own IP address to a block list. I have not yet discovered if the global IPBan database is publicly available.
A couple other things I noted:
The ipban.config
file was completely overwritten by the version at the GetUrlConfig
, including the GetUrlConfig
value! The next time I restarted the IPBAN service, it did not pick up the config from that URL, as the GetUrlConfig
option was now blank. I updated the GetUrlConfig
value on ipban.config
locally and on the remotely hosted ipban.example.config
to include the URL to itself, so that it would persist after a restart.
The FirewallRules
config option has a somewhat confusing syntax, at least for Deny rules. I added the following rule, which then appeared in my Windows Defender Firewalls block rules as IPBan_EXTRA_GoogleDNS_0
:
<add key="FirewallRules" value="
GoogleDNS;block;8.8.4.4;53;.
"/>
This rule allows inbound port 53/tcp traffic from 8.8.4.4 and blocks it from all other ports (0-52/tcp and 54-65535/tcp). I’m still not sure how to specify that I want to block all ports, or block both TCP and UDP traffic using this config option.
IPBan has a lot of other configuration options that I’m excited to test. For me, this tool fills a major gap for Windows servers!
Based on a comment in IPBan’s
logfile.txt
, it looks like access to the global IPBan database is a paid feature:IPBan Pro offers access to 2 threat intel feeds:
Jeff Johnson (IPBan creator) here. Thanks for your very wonderful article.
The recent and naughty lists are indeed paid features and are aggregated from the default banned ip handler being set to true. There is quite an intense amount of processing that I do on submissions with machine learning and other proprietary techniques, hence it being a paid feature. You wouldn’t believe how many botnets attack this submission end point. I get hundreds, sometimes thousands of submissions per second, especially when the botnets start flooding it.
There is another offering, not by me, called AbuseDb that relies on manual submissions. I always thought that this just doesn’t scale to be world reaching and really block out the botnets which is why I’ve gone the automated route. But AbuseDb is still a good product.
The firewall rules is a bit less intuitive, sorry for that. The port on it is always an allow port. So if you are specifying an allow rule, the port will be used as is. If you are specifying a block rule, the port will be inverted so that all other ports are blocked, but the port you specify remains open. Let me know if that helps at all…
Is there a way to automatically whitelist an IP based on a successful login? My client is concerned that one legitimate user forgetting their password could lockout everyone at that location.
That’s definitely a concern, and one I’ve run into. A small office was all behind the same NAT, so all systems appeared to have the same IPv4 address to the target server. With fairly aggressive IPBan settings, the users easily triggered a ban with a handful of typos.
There’s nothing that automatically adds an IP to an allow list after a successful login, but that’s a feature that the developer (Jeff Johnson) might entertain. The best way I’ve found to submit feature requests is via IPBan’s Discord.
You could host your own dynamic allow list based on successful logins which could then be consumed by IPBan. Here’s the relevant section of the
ipban.config
file:It’s not clear to me how frequently a URL value would be queried.
Does anyone has experience on using it in Exchange servers? Appreciate any suggestion.
CrowdSec is available for windows environments too and should do the work you’d expect.
The port is also optional on the custom firewall rule, so if you want to block all ports, just leave it empty