Windows Server Hardening
Windows Server is a high-value target for adversaries: it hosts shared services, stores sensitive data, and often operates with elevated network trust. Hardening reduces the exposure window and limits blast radius when an endpoint or user account is compromised. This guide covers the CIS Benchmarks for Windows Server 2019/2022, Microsoft Security Baselines, and DISA STIGs.
Scope: Applies to member servers, domain controllers, and standalone installations. Domain controller-specific controls are called out where they differ.
1. Minimal Installation โ Reduce Attack Surface From Day One
The single most effective hardening action is installing only what you need.
Windows Server Core
Prefer Server Core (no GUI) where the workload supports it. Removing the graphical shell eliminates:
- Internet Explorer / Edge (browser attack surface)
- Windows Explorer shell (LOLBin execution paths)
- Many desktop-class components with historically high vulnerability density
Server Core is manageable via PowerShell remoting, Windows Admin Center, and RSAT from an admin workstation. Most server roles (AD DS, DNS, DHCP, File Services, Hyper-V, IIS) run on Core.
Remove Unused Roles and Features
After installation, audit installed roles and features and remove anything not required:
# List installed features
Get-WindowsFeature | Where-Object { $_.InstallState -eq 'Installed' } | Select Name, DisplayName
# Remove a feature (example: Telnet client)
Remove-WindowsFeature Telnet-Client
# Remove multiple features
Remove-WindowsFeature Web-DAV-Publishing, TFTP-Client, SMB1Protocol
Always disable/remove:
| Component | Risk | Action |
|---|---|---|
| SMBv1 | EternalBlue / WannaCry | Remove-WindowsFeature FS-SMB1 |
| Telnet client | Cleartext credential exposure | Remove |
| FTP server (IIS) | Cleartext auth | Remove or replace with SFTP |
| Web-DAV | Authenticated RCE attack surface | Remove if not required |
| PowerShell v2 | Bypasses all modern logging | Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root |
| LLMNR | Credential theft (Responder) | Disable via GPO |
| NetBIOS over TCP/IP | Credential theft | Disable on all NICs |
| WDigest auth | Cleartext passwords in LSASS | HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest\UseLogonCredential = 0 |
2. Account Hardening
Rename and Disable Built-in Accounts
| Account | Action |
|---|---|
Administrator |
Rename to a non-obvious name; use LAPS for password management |
Guest |
Disable โ should already be disabled; verify it is |
DefaultAccount |
Disable |
# Rename local administrator
Rename-LocalUser -Name "Administrator" -NewName "svc_localadmin"
# Disable Guest
Disable-LocalUser -Name "Guest"
# Verify no unexpected enabled local accounts
Get-LocalUser | Where-Object { $_.Enabled -eq $true } | Select Name, LastLogon
Local Administrator Password Solution (LAPS)
Deploy LAPS to every server โ identical local admin passwords across servers allow lateral movement with a single credential theft.
- Rotate every 30 days
- Store recovery passwords in Active Directory with access-controlled read permissions
- Audit all LAPS password reads in AD
Service Accounts
- Use Group Managed Service Accounts (gMSA) for services that support it โ passwords managed automatically by AD, no human-readable password
- For services requiring standard accounts: use dedicated, least-privilege service accounts โ never reuse credentials across services
- Do not use Domain Admin or built-in accounts as service accounts
- Enable Protected Users group for privileged accounts
Password Policy (Local / Fine-Grained)
| Policy | Recommended Value |
|---|---|
| Minimum password length | 14 characters |
| Password complexity | Enabled |
| Maximum password age | 60 days (or use MFA + longer rotation) |
| Account lockout threshold | 5 invalid attempts |
| Account lockout duration | 15 minutes |
| Lockout observation window | 15 minutes |
For domain environments, use Fine-Grained Password Policies (PSOs) to enforce stricter requirements for privileged accounts.
3. Network Protocol Hardening
Disable SMBv1
SMBv1 is the protocol exploited by EternalBlue (MS17-010), which enabled WannaCry and NotPetya. It must be disabled on all servers regardless of patch status.
# Remove SMBv1 (Server 2016+)
Remove-WindowsFeature FS-SMB1
# Disable via registry (belt-and-suspenders)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" `
-Name "SMB1" -Value 0 -Type DWord
# Verify
Get-SmbServerConfiguration | Select EnableSMB1Protocol
SMBv2/v3 Hardening
# Require SMB signing (prevent relay attacks)
Set-SmbServerConfiguration -RequireSecuritySignature $true -Force
Set-SmbClientConfiguration -RequireSecuritySignature $true -Force
# Enable SMB encryption (SMBv3, for sensitive data)
Set-SmbServerConfiguration -EncryptData $true -Force
# Disable SMB compression if not required (CVE-2020-0796 / SMBGhost attack vector)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" `
-Name "DisableCompression" -Value 1 -Type DWord
Remote Desktop Protocol (RDP)
If RDP is required, harden it:
| Setting | Value |
|---|---|
| Network Level Authentication (NLA) | Required โ authenticate before session establishment |
| RDP port | Consider non-standard port as obscurity layer (not a security control) |
| Encryption level | High (128-bit) |
| Restrict RDP access | Firewall + AD group membership โ not all users |
| MFA for RDP | Enforce via RD Gateway or Azure AD Conditional Access |
| Idle session timeout | 15 minutes disconnect, 1 hour logoff |
# Require NLA
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" `
-Name "UserAuthentication" -Value 1
# Set encryption level to High
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" `
-Name "MinEncryptionLevel" -Value 3
Restrict RDP access by Group Policy:
Computer Configuration โ Windows Settings โ Security Settings โ
Local Policies โ User Rights Assignment โ
Allow log on through Remote Desktop Services: [specific group only]
Disable LLMNR and NetBIOS
Both are exploited by tools like Responder to capture NTLMv2 hashes via poisoning attacks.
# Disable LLMNR via GPO:
Computer Configuration โ Administrative Templates โ
Network โ DNS Client โ Turn off multicast name resolution: Enabled
# Disable NetBIOS via DHCP scope option or per-adapter registry:
HKLM\SYSTEM\CurrentControlSet\Services\NetBT\Parameters\Interfaces\{GUID}\NetbiosOptions = 2
4. Windows Firewall
Enable and configure the Windows Firewall on all profiles (Domain, Private, Public) even for servers behind a perimeter firewall โ defence in depth.
# Enable all profiles
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
# Set default policy: block all inbound, allow established outbound
Set-NetFirewallProfile -DefaultInboundAction Block -DefaultOutboundAction Allow
# Verify
Get-NetFirewallProfile | Select Name, Enabled, DefaultInboundAction, DefaultOutboundAction
Only open ports for services explicitly running on the server. Common server roles:
| Role | Required Inbound Ports |
|---|---|
| Domain Controller | 53/TCP+UDP, 88, 135, 389, 445, 464, 636, 3268, 3269, 49152โ65535 (RPC) |
| DNS Server | 53/TCP+UDP |
| DHCP Server | 67/UDP |
| File Server | 445/TCP |
| Web Server (IIS) | 80/TCP, 443/TCP |
| RDP (if required) | 3389/TCP โ restrict source to jump host IPs only |
Log all dropped packets:
Set-NetFirewallProfile -LogFileName "%systemroot%\system32\LogFiles\Firewall\pfirewall.log" `
-LogMaxSizeKilobytes 32767 -LogBlocked True -LogAllowed False
5. Privileged Access and UAC
User Account Control (UAC)
UAC should be enabled and set to prompt for credentials (not consent) even on servers.
| Registry Key | Value | Meaning |
|---|---|---|
ConsentPromptBehaviorAdmin |
2 |
Prompt for credentials (not just consent) |
EnableLUA |
1 |
UAC enabled |
PromptOnSecureDesktop |
1 |
Use secure desktop for prompts |
Restrict Interactive Logon
Computer Configuration โ Windows Settings โ Security Settings โ
Local Policies โ User Rights Assignment
| Right | Restriction |
|---|---|
| Allow log on locally | Administrators only (no service accounts) |
| Deny log on as a batch job | Guest, Anonymous |
| Deny log on as a service | Administrator, Guest |
| Allow log on through RD Services | Specific group only (not Domain Users) |
| Access this computer from the network | Remove Everyone; restrict to specific groups |
Tiered Administration Model
Align with Microsoft's Enterprise Access Model (formerly tier model):
- Tier 0: Domain Controllers, PKI, ADFS โ access only from Tier 0 PAWs
- Tier 1: Member servers โ access only from Tier 1 PAWs
- Tier 2: Workstations โ standard admin workstations
Never use Tier 0 credentials on Tier 1 or Tier 2 systems.
6. Credential Protection
Credential Guard / Protected Users
Enable Credential Guard on Hyper-V capable servers to isolate LSASS from process injection:
Computer Configuration โ Administrative Templates โ
System โ Device Guard โ Turn On Virtualization Based Security
Credential Guard: Enabled with UEFI lock
Enrol all privileged accounts in the Protected Users security group:
- Prevents NTLM authentication (Kerberos only)
- Prevents credential delegation
- Enforces 4-hour TGT lifetime
Restrict WDigest and Credential Caching
# Disable WDigest (cleartext passwords in memory)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest" `
-Name "UseLogonCredential" -Value 0
# Limit cached domain credentials (set to 0 on servers; they should have DC connectivity)
# Via GPO: Computer Configuration โ Windows Settings โ Security Settings โ
# Local Policies โ Security Options โ
# Interactive logon: Number of previous logons to cache = 0
7. Patch Management
Unpatched servers are the leading cause of ransomware and data breach incidents.
| Severity | Patch Deadline |
|---|---|
| Critical (CVSS 9.0+) | 48โ72 hours; emergency change if actively exploited |
| High (CVSS 7.0โ8.9) | 7โ14 days |
| Medium (CVSS 4.0โ6.9) | 30 days |
| Low | 90 days |
- Use WSUS, SCCM, or Intune for managed deployment
- Stage patches: DEV โ TEST โ PROD with a defined rollout window
- Track compliance with a dashboard โ target 95% within SLA
- Patch third-party software (redistributables, .NET, VCRedist) on the same cadence
- Subscribe to MSRC Security Update Guide notifications
8. Audit Policy and Event Logging
Enable comprehensive audit policy via Group Policy under:
Computer Configuration โ Windows Settings โ Security Settings โ Advanced Audit Policy Configuration
| Category | Subcategory | Setting |
|---|---|---|
| Account Logon | Credential Validation | Success + Failure |
| Account Management | User Account Management | Success + Failure |
| Account Management | Security Group Management | Success + Failure |
| Account Management | Computer Account Management | Success + Failure |
| Detailed Tracking | Process Creation | Success |
| DS Access | Directory Service Access | Success + Failure |
| Logon/Logoff | Logon | Success + Failure |
| Logon/Logoff | Special Logon | Success |
| Logon/Logoff | Account Lockout | Failure |
| Object Access | File System | Failure (targeted) |
| Object Access | SAM | Failure |
| Policy Change | Audit Policy Change | Success + Failure |
| Policy Change | Authentication Policy Change | Success |
| Privilege Use | Sensitive Privilege Use | Success + Failure |
| System | Security State Change | Success + Failure |
| System | Security System Extension | Success |
PowerShell Logging
Computer Configuration โ Administrative Templates โ Windows Components โ Windows PowerShell
- Script Block Logging: Enabled
- Module Logging: Enabled
- Transcription: Enabled (to central share)
Event Log Sizing
# Increase Security log size (default 20MB is insufficient)
wevtutil sl Security /ms:1073741824 # 1 GB
# Also expand Application and System
wevtutil sl Application /ms:104857600 # 100 MB
wevtutil sl System /ms:104857600
Forward Logs to SIEM
Configure Windows Event Forwarding (WEF) or the SIEM agent to ship events in real time. Minimum retention: 90-day hot, 1-year cold.
Critical events to alert on:
| Event ID | Description |
|---|---|
| 4625 | Failed logon (threshold alert: >5 in 5 min) |
| 4648 | Explicit credential logon (pass-the-hash indicator) |
| 4672 | Special privileges assigned to new logon |
| 4698/4702 | Scheduled task created/modified |
| 4719 | System audit policy changed |
| 4720/4722/4728 | User account created / enabled / added to privileged group |
| 4732 | Member added to a built-in privileged group |
| 4769 | Kerberos service ticket request (watch for RC4 encryption type) |
| 7045 | New service installed |
| 4104 | PowerShell Script Block (malicious content) |
9. Encryption at Rest
- OS drive: BitLocker with TPM 2.0; store recovery keys in AD
- Data drives: BitLocker or application-level encryption for sensitive data
- Backups: Encrypt backup media and verify encryption before offsite transport
- Database files: Enable TDE for SQL Server; use column-level encryption for PII/secrets
# Enable BitLocker on OS drive with TPM
Enable-BitLocker -MountPoint "C:" -TpmProtector
# Add recovery key and back up to AD
Add-BitLockerKeyProtector -MountPoint "C:" -RecoveryPasswordProtector
Backup-BitLockerKeyProtector -MountPoint "C:" -KeyProtectorId (Get-BitLockerVolume C:).KeyProtector[1].KeyProtectorId
10. Domain Controller Specific Controls
If the server is a domain controller, apply additional restrictions:
Protect the SYSVOL and NTDS.DIT
- Restrict SYSVOL access โ it should not be writable by standard users
- Enable file auditing on
%SYSTEMROOT%\SYSVOLand%SYSTEMROOT%\ntds - Protect
ntds.ditwith BitLocker and tight NTFS permissions
Tier 0 Access Restrictions
# Via GPO on Domain Controllers OU:
Deny log on locally: All accounts except designated Tier 0 admin accounts
Allow log on locally: Domain Controllers OU Admin group only
Deny access to this computer from the network: Everyone (use explicit allow instead)
AdminSDHolder and ACL Hygiene
Review AdminSDHolder permissions annually. Any unexpected users with GenericAll, WriteDacl, or WriteOwner permissions on AdminSDHolder can gain domain admin equivalent rights.
# List effective permissions on AdminSDHolder
$AdminSDHolder = [ADSI]"LDAP://CN=AdminSDHolder,CN=System,DC=domain,DC=local"
$AdminSDHolder.ObjectSecurity.Access | Select IdentityReference, ActiveDirectoryRights
Protect KRBTGT
- Reset the
krbtgtaccount password twice (replication latency) immediately after any suspected domain compromise - Schedule annual
krbtgtpassword rotation as a preventive measure (use Microsoft's KRBTGT Reset Script)
Hardening Checklist
| Control | Priority | Verify With |
|---|---|---|
| Server Core or minimal feature install | High | Get-WindowsFeature |
| SMBv1 removed | Critical | Get-SmbServerConfiguration |
| SMB signing enforced | High | Get-SmbServerConfiguration |
| NetBIOS and LLMNR disabled | High | GPO audit / Wireshark |
| WDigest disabled | Critical | Registry check |
| LAPS deployed | Critical | AD attribute / LAPS UI |
| Built-in Administrator renamed | Medium | Get-LocalUser |
| Guest account disabled | High | Get-LocalUser |
| UAC at credential-prompt level | Medium | Registry ConsentPromptBehaviorAdmin = 2 |
| BitLocker on OS and data drives | High | Get-BitLockerVolume |
| Windows Firewall on all profiles | High | Get-NetFirewallProfile |
| Advanced audit policy configured | High | auditpol /get /category:* |
| PowerShell Script Block Logging | High | GPO audit |
| Event log size โฅ 512 MB (Security) | Medium | wevtutil gl Security |
| Logs forwarded to SIEM | High | SIEM connectivity check |
| Critical CVEs patched within 72h | Critical | Patch compliance report |
| NLA enforced for RDP | High | Registry / GPO |
| RDP restricted to admin group + source IP | High | Firewall rule audit |
| Credential Guard enabled (if Hyper-V) | High | msinfo32 โ VBS |
| PowerShell v2 removed | Medium | Get-WindowsOptionalFeature |
| Domain Controllers: Tier 0 logon restrictions | Critical | GPO on DC OU |