jan-karel.com

Windows Hardening

Windows Hardening

Windows Hardening

Network Boundaries That Truly Matter

In network security, structure wins over improvisation: clear paths, fewer privileges, and explicit trust boundaries.

For Windows Hardening, the foundation remains the same: less implicit trust and more visibility into anomalous behavior.

This way you limit not only the chance of incidents, but especially the scope and duration when something does go wrong.

Immediate measures (15 minutes)

Why this matters

The core of Windows Hardening is risk reduction in practice. Technical context supports the choice of measures, but implementation and assurance are central.

Introduction

In 1988, Microsoft brought in a man who would change the face of the company forever, although nobody knew it at the time. Dave Cutler, the legendary engineer behind DEC's VMS operating system, was tasked with building a new, secure, enterprise-grade operating system. The result, released in 1993, was called Windows NT — and it was, for its time, an impressive feat of security architecture. Discretionary access controls. Security tokens. A clean-room design that deliberately broke with the chaos of Windows 3.1 and MS-DOS. Cutler built security into the foundation, not as a layer on top.

Nine years later, on January 15, 2002, Bill Gates sent a now-legendary internal memo to all Microsoft employees. The subject: Trustworthy Computing. "In the past," Gates wrote, "we've made our software and services more compelling for users by adding new features and functionality. [...] Going forward, we must dedicate ourselves to providing customers with a computing experience that is as safe, secure, and reliable as the telephone, water, and electricity services they rely on every day." It was the moment when Microsoft, after years of Code Red, Nimda, and SQL Slammer, officially pivoted to security as a top priority.

And yet, more than twenty years after that memo and more than thirty years after Dave Cutler's security architecture, most Windows servers still have the Print Spooler running. It's as if you spent thirty years developing the most advanced burglar alarm system in the world, installed it in every house, and then discovered that nobody ever turned it on — because the manual is 300 pages long and the alarm goes off when you open the front door.

Windows is the most widely used operating system in business environments. It is also the operating system with the most security features. And it is also the operating system where the most security features are disabled by default.

That is not a paradox. That is a design choice. Microsoft builds security in, but does not enable it, because compatibility always wins over security. A feature that is enabled by default and breaks something generates a support ticket. A feature that is disabled by default and is never enabled generates a pentest report. And support tickets cost Microsoft money. Pentest reports cost you money. Gates' memo changed the culture of Microsoft. It did not change the defaults. And in security, defaults are everything.

This chapter covers standalone Windows hardening — independent of Active Directory. The measures here apply to both workstations and servers. We cover GPO baselines, credential protection, application whitelisting, PowerShell security, AMSI, firewall configuration, logging, and service hardening. Everything you can do to lock down a Windows system without needing a domain controller.

Because ultimately, a domain is only as strong as its weakest endpoint. And that endpoint runs Windows. With Print Spooler enabled. As always. As it has always been. As it probably still will be when the next edition of this book is published.

GPO Security Baselines

Microsoft provides ready-made security baselines via the Security Compliance Toolkit (SCT). These baselines contain GPO configurations that have been tested and recommended by Microsoft itself. The Center for Internet Security (CIS) publishes comparable benchmarks, often stricter than Microsoft's defaults.

Importing baselines

# Download Security Compliance Toolkit
# https://www.microsoft.com/en-us/download/details.aspx?id=55319

# Import a baseline into Group Policy
# Step 1: Open the baseline with Policy Analyzer (part of SCT)
# Step 2: Compare with current configuration
# Step 3: Export delta as GPO backup

# Via LGPO.exe (locally, without domain)
.\LGPO.exe /g .\BaselineGPO\

# Via Group Policy Management (in a domain)
# Import the GPO backup via "Import Settings" on a new GPO object

Applying CIS Benchmarks

# CIS-CAT Pro Assessor -- scan current configuration
.\Assessor-CLI.bat -b .\benchmarks\CIS_Microsoft_Windows_Server_2022.xml

# Or manually via auditpol and registry
# Check a specific setting:
Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" `
    -Name "EnableSmartScreen"

Important GPO settings

Setting Path Recommended value Purpose
Credential Guard Computer\Admin Templates\System\Device Guard Enabled with UEFI lock Isolate LSASS
LSA Protection HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RunAsPPL 1 Block LSASS dumping
SMB Signing Computer\Policies\Network\Lanman Server Required Prevent relay attacks
Deny NTLMv1 Security Settings\Local Policies\Security Options Send NTLMv2 only, refuse LM & NTLM Block downgrade
Disable WDigest HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest UseLogonCredential = 0 No plaintext passwords
Remote Desktop NLA Computer\Admin Templates\Windows Components\Remote Desktop Enabled Prevent pre-auth attacks
Print Spooler services.msc Disabled (unless needed) Eliminate PrintNightmare
Disable LLMNR Computer\Admin Templates\Network\DNS Client Turn off multicast name resolution Block poisoning
Disable NetBIOS Network adapter > TCP/IPv4 > WINS Disable NetBIOS over TCP/IP Block NBNS poisoning
PowerShell v2 Windows Features Removed No logging bypass

Credential Guard & LSA Protection

Credential Guard and LSA Protection are the two most important measures against credential theft on Windows. They protect the LSASS process — the process that manages all authentication credentials — against dumping and injection.

Credential Guard

Credential Guard uses Virtualization-Based Security (VBS) to create an isolated container in which Kerberos tickets and NTLM hashes are stored. Even an attacker with SYSTEM privileges cannot access these credentials.

# Enable Credential Guard via registry
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard" /v EnableVirtualizationBasedSecurity /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LsaCfgFlags /t REG_DWORD /d 1 /f

# Check if Credential Guard is active
Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard |
    Select-Object -ExpandProperty SecurityServicesRunning
# Value 1 = Credential Guard active

# Via GPO: Computer Configuration > Administrative Templates >
#   System > Device Guard > Turn On Virtualization Based Security
#   Credential Guard Configuration: Enabled with UEFI lock

Requirements: UEFI Secure Boot, TPM 2.0 (recommended), Windows 10/11 Enterprise or Server 2016+, and no legacy applications that require NTLM v1 or WDigest.

LSA Protection (RunAsPPL)

LSA Protection configures the LSASS process as Protected Process Light (PPL). This prevents unprotected processes from reading the LSASS memory, even with administrator privileges.

# Enable LSA Protection
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL /t REG_DWORD /d 1 /f

# Check if it is active (after reboot)
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name RunAsPPL

# Result in Event Log
# Event ID 3033: LSA protection mode has been activated
# Event ID 3065: code integrity check failed (suspicious!)

With RunAsPPL enabled, mimikatz sekurlsa::logonpasswords will fail with an access denied. Attackers must then first load a signed kernel driver to bypass PPL — which requires significantly more effort and provides more detection opportunities.

Remote Credential Guard

Remote Credential Guard protects credentials when using RDP. Instead of sending credentials to the remote machine, they remain on the local machine and Kerberos tickets are generated on-the-fly.

# Enable Remote Credential Guard on the client
mstsc /remoteGuard

# Via GPO (client-side):
# Computer Configuration > Administrative Templates > System > Credentials Delegation
# Restrict delegation of credentials to remote servers: Require Remote Credential Guard

# Via registry (server-side -- allow Remote Credential Guard):
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 0 /f

Credential protection overview table

Measure Protects against Configuration Requirements
LSA Protection (RunAsPPL) LSASS memory read, unprotected injection Registry RunAsPPL = 1 Windows 8.1+ / Server 2012 R2+
Remote Credential Guard Credential theft via RDP GPO + mstsc /remoteGuard Windows 10 1607+
Disable WDigest Plaintext passwords in memory Registry UseLogonCredential = 0 Disabled by default from Win 8.1
Protected Users group NTLM, WDigest, delegation AD group membership Domain functional level 2012 R2+

AppLocker & WDAC

Application whitelisting is the most effective measure against running unauthorized software. Instead of trying to recognize malware (which always lags behind), you only allow approved software.

AppLocker

AppLocker works with rules based on three criteria:

  • Publisher rules: based on digital signature (most flexible and reliable)
  • Path rules: based on file location (convenient but easier to bypass)
  • Hash rules: based on file hash (most restrictive, breaks on updates)
# View current AppLocker policy
Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections

# Create a default AppLocker policy based on current software
Get-AppLockerPolicy -Local | Test-AppLockerPolicy -Path "C:\Program Files\*"

# Create publisher-based rules for everything in Program Files
$rules = Get-ChildItem "C:\Program Files" -Recurse -Include *.exe |
    Get-AppLockerFileInformation |
    New-AppLockerPolicy -RuleType Publisher -User Everyone -Optimize

# Export to XML
$rules | Set-AppLockerPolicy -PolicyObject $_ -Merge

# Check if the Application Identity service is running (required for AppLocker)
Get-Service AppIDSvc | Select-Object Status, StartType
Set-Service AppIDSvc -StartupType Automatic
Start-Service AppIDSvc

AppLocker GPO path: Computer Configuration > Policies > Windows Settings > Security Settings > Application Control Policies > AppLocker

WDAC (Windows Defender Application Control)

WDAC is the successor to AppLocker and operates at the kernel level via code integrity policies. It is more powerful and harder to bypass.

# Create a WDAC policy based on a reference machine
New-CIPolicy -Level Publisher -FilePath "C:\Policies\InitialPolicy.xml" `
    -UserPEs -Fallback Hash

# Convert to binary
ConvertFrom-CIPolicy -XmlFilePath "C:\Policies\InitialPolicy.xml" `
    -BinaryFilePath "C:\Policies\InitialPolicy.p7b"

# Deploy the policy
Copy-Item "C:\Policies\InitialPolicy.p7b" `
    "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"

# Audit mode first (recommended!) -- add audit option
Set-RuleOption -FilePath "C:\Policies\InitialPolicy.xml" -Option 3
# Option 3 = Enabled:Audit Mode

AppLocker vs. WDAC

Property AppLocker WDAC
Enforcement level User-mode Kernel-mode
Bypass difficulty Multiple known bypasses Significantly harder
Management GPO, simple SCCM/Intune, more complex
Edition requirement Enterprise/Education All editions (Win 10+)
Suitable for Workstations, quick wins Servers, high security
Catalog signing No Yes
Managed installer No Yes

In practice: start with AppLocker in audit mode on workstations. Use WDAC for servers and high-security environments. And expect that the first year will mainly consist of figuring out which obscure applications your organization runs that have no digital signature at all.

PowerShell security

PowerShell is the favorite tool of both system administrators and attackers. The defense does not consist of disabling PowerShell (that breaks too much), but of maximizing visibility and limiting capabilities.

Constrained Language Mode (CLM)

CLM restricts PowerShell to a subset of functionality. No .NET objects, no COM objects, no Add-Type. Most attack tools do not work in CLM.

# Check current language mode
$ExecutionContext.SessionState.LanguageMode
# FullLanguage = unrestricted (bad)
# ConstrainedLanguage = restricted (good)

# CLM is normally enforced via WDAC or AppLocker
# Manually (for testing):
[Environment]::SetEnvironmentVariable('__PSLockDownPolicy', '4', 'Machine')
# Requires reboot; bypassed without AppLocker/WDAC enforcement

Script Block Logging

Logs the full content of every PowerShell script that is executed, including deobfuscated versions. This is essential for forensic investigation.

# Via GPO: Computer Configuration > Administrative Templates >
#   Windows Components > Windows PowerShell > Turn on PowerShell Script Block Logging
# Or via registry:
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 /f

# Events appear in:
# Microsoft-Windows-PowerShell/Operational, Event ID 4104

Module Logging

Logs which PowerShell modules are invoked and with which parameters.

# Via registry:
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" /v EnableModuleLogging /t REG_DWORD /d 1 /f

# Log all modules (wildcard):
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames" /v "*" /t REG_SZ /d "*" /f

# Events in: Microsoft-Windows-PowerShell/Operational, Event ID 4103

Transcription

Saves the complete PowerShell session as a text file — including input and output.

# Via registry:
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v EnableTranscripting /t REG_DWORD /d 1 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v OutputDirectory /t REG_SZ /d "C:\PSTranscripts" /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" /v EnableInvocationHeader /t REG_DWORD /d 1 /f

Disabling PowerShell v2

PowerShell v2 does not support any of the above logging mechanisms. Attackers use powershell -version 2 to bypass logging.

# Check if PowerShell v2 is available
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2

# Remove it
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root -NoRestart
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 -NoRestart

AMSI (Anti-Malware Scan Interface)

AMSI is the bridge between applications and anti-malware products. When PowerShell, VBScript, JScript, or Office macros execute code, that code is sent via AMSI to the installed anti-malware solution for inspection.

What AMSI does

AMSI scans code after deobfuscation. If an attacker executes base64-encoded PowerShell, AMSI sees the decoded version. This makes it effective against many evasion techniques.

AMSI providers: - Windows Defender (default) - Other AV products that support AMSI - Custom AMSI providers via the AMSI COM interface

AMSI bypass detection and mitigation

AMSI bypasses exist because attackers patch the AMSI DLL in memory before their payload is scanned. Common techniques:

  • AmsiScanBuffer patching (overwrite the function with a return-0)
  • Reflection-based bypasses via .NET
  • amsiInitFailed manipulation

Detecting AMSI bypasses:

# Monitor Event ID 1116 (Windows Defender)
# "AMSI detected a bypass attempt"

# Script Block Logging captures AMSI bypass attempts (Event ID 4104)
# Look for patterns such as:
#   [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
#   amsiInitFailed
#   AmsiScanBuffer

# Windows Defender ASR rule: Block Win32 API calls from Office macros
# GUID: 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B
Add-MpPreference -AttackSurfaceReductionRules_Ids 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B `
    -AttackSurfaceReductionRules_Actions Enabled

AMSI provider hardening

# Check registered AMSI providers
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\AMSI\Providers"

# Ensure Windows Defender is active as AMSI provider
# GUID: {2781761E-28E0-4109-99FE-B9D127C57AFE}
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\AMSI\Providers\{2781761E-28E0-4109-99FE-B9D127C57AFE}"

Windows Firewall hardening

The Windows Firewall is one of the best-kept secrets of Windows security. It is a full-featured host-based firewall that, properly configured, forms a significant obstacle to lateral movement. But the default configuration is too permissive.

Default deny inbound

# Set default deny for all profiles
Set-NetFirewallProfile -Profile Domain,Public,Private `
    -DefaultInboundAction Block `
    -DefaultOutboundAction Allow `
    -Enabled True

# Allow essential services
New-NetFirewallRule -DisplayName "Allow RDP from Management VLAN" `
    -Direction Inbound -Protocol TCP -LocalPort 3389 `
    -RemoteAddress 10.0.100.0/24 -Action Allow

New-NetFirewallRule -DisplayName "Allow WinRM from Management VLAN" `
    -Direction Inbound -Protocol TCP -LocalPort 5985,5986 `
    -RemoteAddress 10.0.100.0/24 -Action Allow

Block commonly used risk ports

# Block SMB from outside the local subnet
New-NetFirewallRule -DisplayName "Block SMB Inbound" `
    -Direction Inbound -Protocol TCP -LocalPort 445 `
    -RemoteAddress "!10.0.0.0/8" -Action Block

# Block NetBIOS
New-NetFirewallRule -DisplayName "Block NetBIOS" `
    -Direction Inbound -Protocol TCP -LocalPort 137-139 -Action Block
New-NetFirewallRule -DisplayName "Block NetBIOS UDP" `
    -Direction Inbound -Protocol UDP -LocalPort 137-139 -Action Block

# Block WMI from non-management networks
New-NetFirewallRule -DisplayName "Block WMI Inbound" `
    -Direction Inbound -Protocol TCP -LocalPort 135 `
    -RemoteAddress "!10.0.100.0/24" -Action Block

# Block LLMNR
New-NetFirewallRule -DisplayName "Block LLMNR" `
    -Direction Outbound -Protocol UDP -RemotePort 5355 -Action Block

# Block mDNS
New-NetFirewallRule -DisplayName "Block mDNS" `
    -Direction Outbound -Protocol UDP -RemotePort 5353 -Action Block

GPO deployment

Computer Configuration > Policies > Windows Settings > Security Settings >
  Windows Defender Firewall with Advanced Security

# Import firewall rules via GPO:
# 1. Configure rules on a reference machine
# 2. Export: netsh advfirewall export "C:\fw-baseline.wfw"
# 3. Import via GPO or distribute via SCCM/Intune

Enable firewall logging

# Enable logging for all profiles
Set-NetFirewallProfile -Profile Domain,Public,Private `
    -LogAllowed True `
    -LogBlocked True `
    -LogFileName "C:\Windows\System32\LogFiles\Firewall\pfirewall.log" `
    -LogMaxSizeKilobytes 32768

Audit policy & logging

Windows has an extensive audit framework. The problem is not that it doesn't exist. The problem is that nobody enables it, and when they do enable it, nobody looks at the logs.

Advanced Audit Policy Configuration

:: Enable advanced audit (replaces basic audit)
auditpol /set /subcategory:"Logon" /success:enable /failure:enable
auditpol /set /subcategory:"Logoff" /success:enable
auditpol /set /subcategory:"Special Logon" /success:enable
auditpol /set /subcategory:"Process Creation" /success:enable
auditpol /set /subcategory:"Security Group Management" /success:enable
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Scheduled Task" /success:enable /failure:enable
auditpol /set /subcategory:"Security System Extension" /success:enable

:: Enable command line logging for process creation
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" /v ProcessCreationIncludeCmdLine_Enabled /t REG_DWORD /d 1 /f

:: View current configuration
auditpol /get /category:*

Important Event IDs

Event ID Description Why important
4624 Successful logon Baseline for who logs in, with which type (type 3 = network, type 10 = RDP)
4625 Failed logon Brute force detection, password spray
4648 Logon with explicit credentials Someone is using runas or alternate credentials — suspicious
4672 Special privileges assigned Admin logon detection, privilege escalation
4688 New process created Process tree reconstruction, command line auditing
4698 Scheduled task created Persistence mechanism detection
4720 User account created Unauthorized account creation
4732 Member added to local group Privilege escalation (e.g., addition to Administrators)
7045 Service installed Persistence via services, PSExec detection

Sysmon deployment

Sysmon is the extension to standard Windows logging that every serious environment needs. It logs process creation with parent-child relationships, network connections, file creation, registry changes, and more.

# Download Sysmon from Sysinternals
# Use SwiftOnSecurity's configuration as a starting point:
# https://github.com/SwiftOnSecurity/sysmon-config

# Install Sysmon with configuration
.\Sysmon64.exe -accepteula -i sysmonconfig-export.xml

# Update configuration
.\Sysmon64.exe -c sysmonconfig-export.xml

# Important Sysmon Event IDs:
# 1  - Process Create (with parent, command line, hashes)
# 3  - Network Connection
# 7  - Image Loaded (DLL loading)
# 8  - CreateRemoteThread (process injection)
# 10 - ProcessAccess (LSASS access!)
# 11 - FileCreate
# 13 - RegistryEvent (value set)
# 22 - DNSEvent (DNS queries)

Sysmon Event ID 10 with TargetImage ending in lsass.exe is one of the most valuable detection rules you can implement. It detects credential dumping attempts in real-time.

Service hardening

Every running service is a potential attack surface. Windows runs dozens of services by default, most of which are not needed.

Disabling unnecessary services

Service Risk Action
Print Spooler (Spooler) PrintNightmare, SpoolFool, privilege escalation Disable unless the system is a print server
Remote Registry (RemoteRegistry) Remote registry enumeration Disable
Windows Remote Management (WinRM) Lateral movement via PowerShell Remoting Disable unless managed via management VLAN
NetBIOS over TCP/IP NBNS poisoning, reconnaissance Disable per adapter
Server (LanmanServer) SMB attacks if SMB is not needed Disable on workstations
Xbox services No business purpose whatsoever Disable
Fax Service It's 2026 Disable
# Disable Print Spooler
Stop-Service -Name Spooler -Force
Set-Service -Name Spooler -StartupType Disabled

# Disable Remote Registry
Stop-Service -Name RemoteRegistry -Force
Set-Service -Name RemoteRegistry -StartupType Disabled

# Bulk: disable multiple services
$services = @('Spooler', 'RemoteRegistry', 'Fax', 'XblAuthManager', 'XblGameSave')
foreach ($svc in $services) {
    Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
    Set-Service -Name $svc -StartupType Disabled -ErrorAction SilentlyContinue
    Write-Host "[+] Disabled: $svc"
}

Service accounts: gMSA

Use Group Managed Service Accounts (gMSA) instead of regular user accounts for services. gMSAs have automatically rotated, 240-character-long passwords that do not need to be managed by humans.

# Create a gMSA (requires AD)
New-ADServiceAccount -Name "svc_webapp" `
    -DNSHostName "svc_webapp.corp.local" `
    -PrincipalsAllowedToRetrieveManagedPassword "WebServers$"

# Install on the target server
Install-ADServiceAccount -Identity "svc_webapp"

# Test
Test-ADServiceAccount -Identity "svc_webapp"

# Configure the service to use the gMSA
# Service > Properties > Log On > This account: CORP\svc_webapp$

A service account with a password stored in an Excel spreadsheet that is manually rotated every three years is a service account that has already been compromised. You just don't know it yet.

There is something deeply ironic about an operating system that has more than six hundred Group Policy settings for security, but enables exactly zero of them by default. Microsoft builds Credential Guard, AppLocker, WDAC, CLM, Script Block Logging, AMSI, ASR rules, Exploit Guard, and twenty more features — and ships them all in the "off" position.

It's like buying a car with airbags, ABS, lane assist, emergency braking, and blind spot monitoring, but everything is behind a control panel in the trunk that you have to connect yourself. With a manual of three hundred pages. In English. Without illustrations.

And then that Print Spooler. That immortal Print Spooler. There is no service in the history of computing that has produced more CVEs, facilitated more pentests, and required more "critical" patches than the Windows Print Spooler. PrintNightmare. SpoolFool. PrinterBug. Every year a new variant. Every year the same question: "Why is that service even running?" And every year the same answer: "Because Marie from accounting sometimes wants to print a PDF."

Marie. From accounting. On a server. That sits in a data center. Where there is no printer.

"But it's enabled by default!" Yes. That is the point. Windows is an operating system designed for maximum compatibility, not for maximum security. Every feature is enabled by default, every port is open by default, every service runs by default. And we get to lock it down. Feature by feature. Service by service. Registry key by registry key. As if we're building a ship that sinks by default and we have to plug the holes.

The good news: the holes are documented. The bad news: the ship is already sailing.

Common mistakes

Mistake Consequence Solution
Print Spooler enabled on servers PrintNightmare, privilege escalation, coercion Disable on everything except print servers
WDigest enabled Plaintext passwords in LSASS memory Registry: UseLogonCredential = 0
No Script Block Logging No visibility into PowerShell attacks GPO: enable Script Block Logging
PowerShell v2 available Attackers bypass all logging Remove the feature
Local admin password the same everywhere Once cracked = access everywhere Implement LAPS
No Sysmon No process-level visibility Deploy Sysmon with proper config
AppLocker in allow-all mode No application control Configure publisher rules
Firewall logging disabled No visibility into blocked/allowed traffic Enable logging on all profiles
Audit policy on basic instead of advanced Insufficient detail in security logs Enable Advanced Audit Policy
No command line logging for 4688 Process events without context Registry: ProcessCreationIncludeCmdLine_Enabled = 1
Remote Desktop without NLA Pre-authentication attacks possible Require Network Level Authentication

Checklist

# Measure Priority Complexity Impact
1 Disable Print Spooler (non-print servers) Critical Low Eliminates entire class of attacks
2 Enable LSA Protection (RunAsPPL) Critical Low Blocks LSASS dumping
3 Enable Script Block Logging Critical Low Visibility into PowerShell attacks
4 Remove PowerShell v2 Critical Low Prevents logging bypass
5 Disable LLMNR and NetBIOS Critical Low Prevents name poisoning
6 Disable WDigest Critical Low No plaintext credentials
7 Deploy Sysmon High Medium Deep endpoint visibility
8 Configure Advanced Audit Policy High Medium Forensically usable logs
9 Command line logging (4688) High Low Process context in logs
10 Enable Credential Guard High Medium Credential isolation
11 Implement LAPS High Medium Unique local admin passwords
12 Windows Firewall default deny inbound High Medium Host-level segmentation
13 AppLocker in enforce mode High High Application whitelisting
14 Disable unnecessary services Medium Low Reduced attack surface
15 Remote Credential Guard for RDP Medium Medium Credential protection during remote management
16 WDAC for servers Medium High Kernel-level application control
17 Enable firewall logging Medium Low Network visibility at endpoint level
18 Module Logging and Transcription Medium Low Additional PowerShell visibility
19 gMSA for service accounts Medium Medium Automatic password rotation
20 Import security baselines (SCT/CIS) Medium Medium Validated configuration

The first six measures are registry changes or GPO settings that you can roll out in an afternoon. They cost nothing, rarely break anything, and eliminate the most common attack techniques. If you start tomorrow, start there.

Summary

Windows hardening is no mystery. The measures are documented, the tools are built in, and the configuration is largely a matter of GPOs and registry settings. The problem has never been that we don't know what we need to do. The problem is that we don't do it. Credential Guard is disabled because there is a legacy application. AppLocker is in audit mode because nobody dares to press the enforce button. Print Spooler runs because "it has always been that way." And meanwhile we log nothing, monitor nothing, and are surprised when something goes wrong. The common thread through this chapter is simple: enable what Microsoft has built. Start with the six critical measures from the checklist — that takes an afternoon and eliminates eighty percent of common attack techniques. Then build further step by step. And disable that Print Spooler. Now.

In the next chapter, we cover email and DNS hardening: how to configure SPF, DKIM, and DMARC, prevent DNS manipulation, and prevent your mail server from becoming the favorite toy of every spammer and phisher on the internet.

Op de hoogte blijven?

Ontvang maandelijks cybersecurity-inzichten in je inbox.

← Network & Active Directory ← Home