What an RDP brute-force attack actually looks like
Anatomy of the attack that hits every Windows server exposed to the internet: who runs it, what it costs them, why the standard advice only half works, and what stops it.
The attack, in plain terms
An RDP brute-force attack is not a targeted operation. It is a commodity: someone rents a botnet, feeds it a list of IP ranges, and has it try to log in to every machine answering on port 3389. The password list is short and boring — Administrator with Password1, admin with admin, the company name with the current year appended. The bot does not know or care what your server does.
The economics are what make it relentless. A single successful login is worth real money on a ransomware access market, and the cost of an attempt is close to zero. So the bots never stop. Put a fresh Windows Server on a public IP with RDP open and you will typically see the first failed login within an hour, and a steady few thousand a day within a week.
That volume is the important part. A human attacker guessing at your password is a story; a hundred thousand attempts a month from rotating addresses is a weather condition. Defences that assume the first are useless against the second.
How to tell it is happening to you
Windows records every failed logon as event ID 4625 in the Security log. Open Event Viewer, go to Windows Logs → Security, and filter for 4625. On a quiet server you will see a handful from users fumbling their passwords. Under attack you will see a wall.
The tell is not the count on its own, it is the shape. A user who mistyped a password produces two or three failures from one address, from an account that exists, then stops. A bot produces a long run against account names that were never on your machine — admin, sql, backup, test, scanner, user1 — from addresses in hosting ranges you have never dealt with, at a steady rate through the night.
This one-liner gives you the top offending source addresses from the last day:
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-1)} |
ForEach-Object { ([xml]$_.ToXml()).Event.EventData.Data |
Where-Object Name -eq 'IpAddress' | Select-Object -ExpandProperty '#text' } |
Group-Object | Sort-Object Count -Descending | Select-Object -First 20 Count, NameWhy the usual advice only half works
Every hardening checklist opens with "use a strong password". It is correct and it is not enough. A strong password means the bots will not guess it — but they will keep trying forever, and every attempt costs you a thread, an audit-log line and a slice of the CPU. Servers under sustained attack get measurably slower, and the security log rotates so fast that the one event you actually needed is gone.
The next line is usually "turn on Account Lockout Policy". Be careful with that one. Lockout counts failures per account, and the bots are guessing account names off a list. Lock out Administrator after five bad attempts and an attacker who never had a chance of guessing the password can now disable that account at will, from anywhere, forever. You have converted a nuisance into a denial of service against yourself.
Network Level Authentication genuinely helps — it forces the client to authenticate before a session is created, which removes a class of pre-auth exploits and cuts the resource cost of each attempt. Turn it on. It does not reduce the attempt rate.
A VPN in front of RDP is the strongest answer available and the one most organisations cannot actually adopt: it means every contractor, every phone, every emergency 3 a.m. login goes through more infrastructure that also has to be maintained and paid for. If you can do it, do it. Most of the servers being attacked right now belong to people who cannot.
What actually reduces the attempts
The only thing that changes the volume is refusing to talk to the source. Everything else negotiates with it.
That means watching the failure stream, and when one address crosses a threshold, adding it to a firewall rule that drops its packets before Windows spends anything on them. This is what fail2ban does on Linux, and there is no built-in Windows equivalent — which is why so many administrators end up writing a scheduled PowerShell script to do it.
Three details separate a defence that holds from one that leaks:
- Ban the subnet, not the address. Bots run on hosting ranges. Block 203.0.113.47 and 203.0.113.48 starts an hour later. Blocking the /24 ends the whole run at once — and legitimate users almost never share a /24 with a scanner.
- Ban permanently, and survive reboots. A one-hour ban means the same botnet is back tonight. The rule has to live in the firewall, not in memory.
- Whitelist yourself first, before anything else is switched on. The single most common way this goes wrong is an administrator who locks their own office IP out of a server they can only reach over RDP.
Consolidate the rules, or the firewall becomes the bottleneck
A detail that only shows up in production: Windows Firewall handles a few large rules far better than thousands of small ones. Scripts that call New-NetFirewallRule once per banned address work beautifully for a fortnight and then start taking minutes to evaluate, because the rule set has grown to five figures.
The fix is to keep one rule whose address list you rewrite, rather than one rule per attacker. It is a small design decision that decides whether the defence still works in six months.
Doing it without writing the script
RDP Protector is that logic packaged as a signed Windows agent. It reads the same 4625 stream you would read, decides locally — so it keeps working if the network drops — and maintains a single consolidated firewall rule containing every banned range.
On install it detects the actual RDP, FTP and MS SQL ports from the registry and the listening sockets, so a server that moved off 3389 is covered without configuration, and it whitelists the IP you are connecting from before it blocks anything.
The part you cannot build alone is the shared reputation: an address that attacked one customer is already blocked for the others before it reaches them. One server is free forever, which is enough to watch a real attack stream on your own machine and decide from evidence.
FAQ
- How many failed RDP logins are normal?
- On a server not exposed to the internet, near zero — a handful a week from people mistyping passwords. On a server with RDP reachable from any address, a few thousand a day is unremarkable and says nothing about you specifically; it is the background rate of internet-wide scanning. What matters is the trend and the source distribution, not the raw number.
- Does changing the RDP port stop brute-force attacks?
- It stops the untargeted scanners that only probe 3389, which in practice is most of the volume — often a 90%+ drop in attempts. It does not stop anything that scans the full port range, and services like Shodan index non-standard RDP ports continuously. Treat it as noise reduction, not as protection.
- Should I enable Account Lockout Policy against brute-force?
- Not as your primary defence on an internet-facing server. Lockout is keyed on the account name, and attackers choose account names freely, so anyone can lock out your Administrator account on demand from any address. Block at the network layer instead, and keep lockout for a modest threshold on interactive accounts if you want it.
- Is blocking a whole /24 subnet too aggressive?
- For an address range that has just thrown hundreds of failed logins at you, rarely. Attack traffic comes from hosting and VPS ranges where neighbouring addresses belong to the same operator; residential users almost never share a /24 with a scanner. Keep a whitelist for your own offices and VPN exits and the false-positive rate is close to zero.
