RDP Remote Desktop Hardening: Brute-Force and Unauthorized Access Controls
RDP port 3389 remains a primary target for brute force and ransomware. This guide covers account lockout, NLA, port change, firewall restriction, and MFA for a complete Windows Server Remote Desktop hardening plan, with PowerShell commands and verification steps.
Scope
RDP (port 3389) is among the most scanned and brute-forced services on the Internet. Attackers dictionary-attack weak passwords; once in, they own the server and drop ransomware or crypto-miners. Applies to: Windows Server production hosts exposing 3389, environments with frequent brute-force log alerts that need emergency hardening, and teams that must meet MLPS remote-ops security requirements.
Prerequisites
- Windows Server 2016/2019/2022 or Windows 10/11 Pro
- PowerShell or CMD as Administrator
- Confirm current RDP access path (direct Internet / VPN or bastion)
- Keep a backup management channel (console or IPMI) before hardening to avoid lockout
Mechanism
RDP brute force is 3389 + weak password. Attackers run Hydra, msf, and similar tools against Administrator and peer accounts. Windows account lockout threshold is off by default, so attempts are unlimited — primary cause of compromise. Hardening is four layers:
- Ingress reduction: enable NLA, change default port, restrict source IPs
- Password policy: enable account lockout to stop sustained brute force
- Transport encryption: TLS or a higher security level
- MFA: TOTP/SMS so a leaked password is not enough
Procedure
Step 1: Enable NLA (mandatory)
NLA requires credential validation before the remote session is established. Filters most unauthenticated brute-force traffic:
`# PowerShell (run as Administrator): enable NLA
Set-ItemProperty -Path \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\\\\WinStations\\\\RDP-Tcp\" -Name \"UserAuthentication\" -Value 1
# Restart the Remote Desktop service for the change to take effect
Restart-Service TermService`
Step 2: Account lockout policy (core anti-brute-force)
Lock after 5 failures for 30 minutes. Stops dictionary attacks (key parameters):
`# Use net accounts to set the lockout policy
net accounts /lockoutthreshold:5
net accounts /lockoutduration:30
net accounts /lockoutwindow:30
# Review the policy to confirm
net accounts | findstr /i \"lockout\"`
Step 3: Change default port and add firewall allowlist
`# 1) Change the RDP port to 53389 (example) to avoid mass scanning of default 3389
$port = 53389
Set-ItemProperty -Path \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\\\\WinStations\\\\RDP-Tcp\" -Name \"PortNumber\" -Value $port
# 2) Firewall: allow only specified IPs to access the new port (example: your office egress IP)
New-NetFirewallRule -DisplayName \"RDP-Allow-Office\" -Direction Inbound -Protocol TCP -LocalPort $port -RemoteAddress \"203.0.113.10\" -Action Allow
Remove-NetFirewallRule -DisplayName \"RDP-Default\" -ErrorAction SilentlyContinue
# 3) Restart the service and confirm the listening port
Restart-Service TermService
netstat -an | findstr $port`
Step 4: Restrict accounts and harden transport
`# 1) Disable blank-password remote logon and the Guest account
Set-ItemProperty -Path \"HKLM:\\\\SYSTEM\\\\CurrentControlSet\\\\Control\\\\Lsa\" -Name \"LimitBlankPasswordUse\" -Value 1
Disable-LocalUser -Name \"Guest\" -ErrorAction SilentlyContinue
# 2) Remove unnecessary accounts from the Remote Desktop Users group; keep administrators only
net localgroup \"Remote Desktop Users\" | findstr /v \"command\"`
Verification
`# 1) Confirm the new port is in effect (should see 0.0.0.0:53389)
netstat -an | findstr 53389
# 2) Simulate 6 incorrect passwords to verify the account is locked
# After 6 consecutive wrong passwords in mstsc, the system should report the account is locked
# 3) Confirm the firewall rule (whitelist IPs only)
Get-NetFirewallRule -DisplayName \"RDP-Allow-Office\" | Get-NetFirewallAddressFilter
# 4) Check that Security log 4625 (logon failure) events are no longer growing continuously
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} -MaxEvents 5 | Select TimeCreated,Message`
FAQ
FAQ 1: Cannot connect remotely after changing the port?
Confirm the new port is allowed in the firewall and the client specifies it (in mstsc, set Computer to IP:53389). If it still fails, from the server console (cloud vendor web terminal) run netstat -an | findstr 53389, check listen state, and confirm TermService restarted. Rehearse the full flow on a test host first.
FAQ 2: Will account lockout lock out legitimate ops?
Minor impact: five consecutive wrong passwords locks the account for 30 minutes. Mitigate: give operators unique accounts (do not share Administrator), set threshold to 5–10, duration 15–30 minutes, and combine with IP allowlisting to cut false lockouts.
FAQ 3: Is port change plus NLA enough?
No. Port hiding only lowers bulk-scan hit rate; targeted scans still find it. NLA filters unauthenticated traffic, not password guessing. Stack account lockout + IP allowlist. High-risk environments add TOTP MFA (Duo, FreeOTP) for defense in depth.
Summary
RDP hardening order: stop brute force first (account lockout), then shrink ingress (NLA + port + IP allowlist), then add MFA. Internet-exposed servers must complete the first three layers. Prefer placing RDP behind VPN or a bastion — zero public exposure is the most stable architecture. After hardening, watch Security log 4625 events and confirm brute-force volume hits zero.