Introduction
A default Windows installation is not a secure baseline — it's a starting point. Out of the box, Windows ships with legacy protocols enabled, weak default policies, and services running that most endpoints will never need. For a red teamer, this is opportunity. For a defender, it's debt.
Windows hardening is the disciplined process of reducing attack surface before an adversary finds it. The goal isn't perfection — it's raising the cost of exploitation high enough that attackers move on or make noise that detection picks up. This guide covers the layers that matter most: storage, identity, network, application control, and PowerShell — the attacker's favorite tool turned against them.
Red team perspective: Every item in this guide is something I look for being absent during an engagement. If you skip even one section, assume a competent attacker will find it.
Storage Security — BitLocker & DMA
Physical access is game over — unless your data at rest is encrypted. BitLocker is the built-in answer, but default settings are not the hardened settings.
BitLocker with XTS-AES 256
The default BitLocker cipher in many environments is still AES-CBC 128-bit. You want XTS-AES 256-bit. XTS mode is resistant to ciphertext manipulation attacks that CBC is vulnerable to, and 256-bit keys provide the headroom you need against future threats. Windows 11 24H2+ supports hardware-accelerated encryption via the SoC, so performance is no longer a reason to downgrade.
Enforce this before encrypting. If a drive is already encrypted with weaker settings, decrypt and re-encrypt.
# Check current BitLocker status and cipher strength
manage-bde -status
# Output to look for:
# Encryption Method: XTS-AES 256
# Protection Status: Protection On
# Key Protectors: TPM, Numerical Password
Set the encryption method via Group Policy before enabling BitLocker:
Computer Configuration
> Administrative Templates
> Windows Components
> BitLocker Drive Encryption
> Operating System Drives
→ "Configure use of hardware-based encryption" → Enabled
→ "Choose drive encryption method and cipher strength" → XTS-AES 256-bit
TPM 2.0 — Hardware Root of Trust
TPM 2.0 seals the BitLocker key against platform state. Without it, the encrypted drive can be decrypted by anyone who knows the recovery key — which attackers extract via memory attacks or Active Directory. Verify TPM is enabled and version 2.0:
Get-Tpm | Select-Object TpmPresent, TpmReady, TpmEnabled, ManufacturerVersion
Kernel DMA Protection
Thunderbolt and PCIe ports can be used to perform Direct Memory Access (DMA) attacks — an attacker plugs in a malicious device and reads arbitrary physical memory, bypassing the OS entirely and extracting BitLocker keys in seconds. Kernel DMA Protection prevents this by restricting DMA operations from external peripherals until they are explicitly authorized.
# Check if Kernel DMA Protection is enabled
(Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard").EnableVirtualizationBasedSecurity
# Also check in System Information (msinfo32):
# Kernel DMA Protection → On
Identity & Access Management
Identity is the new perimeter. Once an attacker has valid credentials — even a low-privilege account — they're no longer an outsider. The question becomes: how much can they do with what they have?
Principle of Least Privilege (PoLP)
No user should run as a local administrator for daily tasks. This is the single most impactful thing you can do. Standard user accounts cannot install software, modify system settings, or write to protected directories — which stops the majority of malware cold at the privilege level it lands with.
whoami /priv and whoami /groups. If the compromised user is a local admin, lateral movement and persistence become trivially easy. PoLP is your single highest-ROI hardening control.
Windows LAPS — Rotating Local Admin Passwords
If every machine in your fleet shares the same local administrator password, one compromised credential = full domain lateral movement. Windows LAPS (built into Windows since the April 2023 update) generates unique, rotating passwords for the built-in local admin account and stores them in Active Directory or Azure AD — readable only by authorized accounts.
# Enable Windows LAPS (requires April 2023+ cumulative update)
# First, update the AD schema to support LAPS attributes
Update-LapsADSchema
# Configure via GPO:
# Computer Configuration > Administrative Templates
# > System > LAPS
# → "Configure password backup directory" → Active Directory
# → "Password Settings" → Complexity: Large letters + small + numbers + specials
# → "Password age (days)" → 30
UAC — Always Notify
UAC is not a security boundary — it's a friction layer. But friction matters. Set it to Always Notify, which prompts on both software installs and any system setting changes, even for administrators. The default "Notify me only when apps try to make changes" can be bypassed via COM object abuse without triggering a UAC prompt.
# Set UAC to Always Notify (value 2 = always notify)
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" `
-Name "ConsentPromptBehaviorAdmin" -Value 2
Account Lockout Policy
Brute-force and password spray attacks are stopped dead by a properly configured lockout policy. The recommended baseline per CIS Benchmark is: lock after 5 invalid attempts, lockout duration of 15 minutes, reset counter after 15 minutes.
Computer Configuration
> Windows Settings
> Security Settings
> Account Policies
> Account Lockout Policy
→ Account lockout threshold: 5 invalid logon attempts
→ Account lockout duration: 15 minutes
→ Reset account lockout counter after: 15 minutes
Firewall Hardening
Windows Defender Firewall is underutilized in most environments. The hardened posture is Default Deny — block everything, then explicitly allow what's needed.
# Enforce firewall on ALL profiles — non-negotiable
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
# Set default inbound action to Block
Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block
# Disable ICMP responses (stealth mode — machine won't respond to pings)
New-NetFirewallRule -DisplayName "Block ICMP Echo Request" `
-Protocol ICMPv4 -IcmpType 8 -Direction Inbound -Action Block
New-NetFirewallRule -DisplayName "Block ICMPv6 Echo Request" `
-Protocol ICMPv6 -IcmpType 128 -Direction Inbound -Action Block
In high-security environments, apply outbound rules too. Restricting outbound traffic to known-good destinations forces malware C2 communication through channels you can monitor and block.
Attacker's view: A machine that doesn't respond to ICMP is invisible in basic network scans. It won't appear in nmap -sn host discovery. This is a small but effective way to reduce your exposure during early reconnaissance phases.
Application Control — WDAC & ASR
Malware almost always executes code. Application control means you decide what code is allowed to run — anything else is blocked at the kernel level before it ever executes.
Windows Defender Application Control (WDAC)
WDAC is the successor to AppLocker, enforced at the kernel level rather than in user-space. This matters because user-space controls (including AppLocker) can be bypassed by processes with the right privileges. WDAC is enforced by the hypervisor and is significantly harder to bypass.
A practical starting policy: allow trusted publishers + Microsoft + specific folders (e.g., C:\Program Files). Anything unsigned or from an untrusted publisher is blocked.
# Generate a starter WDAC policy based on your current system's running apps
# (Audit mode first — never enforce before auditing)
New-CIPolicy -Level Publisher -FilePath "C:\Policies\WDACPolicy.xml" `
-UserPEs -ScanPath "C:\Program Files" -Audit
# Convert XML policy to binary
ConvertFrom-CIPolicy -XmlFilePath "C:\Policies\WDACPolicy.xml" `
-BinaryFilePath "C:\Policies\WDACPolicy.bin"
# Deploy the policy (test in audit mode first)
Copy-Item "C:\Policies\WDACPolicy.bin" `
-Destination "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"
Attack Surface Reduction (ASR) Rules
ASR rules are targeted mitigations for specific attacker techniques — blocking Office macros from spawning child processes, preventing credential theft from LSASS, blocking executable content from email. Each rule has a GUID and targets a specific technique from the MITRE ATT&CK framework.
# Block executable content from email client and webmail
Add-MpPreference -AttackSurfaceReductionRules_Ids BE9BA2D9-53ED-4437-B4F0-E0888FAF706D `
-AttackSurfaceReductionRules_Actions Enabled
# Block Office applications from creating child processes
Add-MpPreference -AttackSurfaceReductionRules_Ids D4F940AB-401B-4EFC-AADC-AD5F3C50688A `
-AttackSurfaceReductionRules_Actions Enabled
# Block credential stealing from LSASS
Add-MpPreference -AttackSurfaceReductionRules_Ids 9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2 `
-AttackSurfaceReductionRules_Actions Enabled
# Block untrusted and unsigned processes that run from USB
Add-MpPreference -AttackSurfaceReductionRules_Ids B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4 `
-AttackSurfaceReductionRules_Actions Enabled
Computer Management
Legacy protocols and default system settings are a goldmine for attackers. These are the controls that get overlooked because they don't have a flashy UI — but they're exactly what Responder, Impacket, and BloodHound rely on.
Disable LLMNR and NetBIOS
LLMNR (Link-Local Multicast Name Resolution) and NBT-NS (NetBIOS Name Service) are legacy name resolution protocols that broadcast queries on the local network. When a machine asks "who is FILESERVER?" and no DNS answer exists, LLMNR broadcasts the question. An attacker running Responder answers that query, captures the NTLMv2 hash, and cracks or relays it.
There is no legitimate reason to have these enabled in a modern Active Directory environment with functioning DNS.
# Disable LLMNR via Registry
New-Item "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" `
-Name "EnableMulticast" -Value 0
# Disable NetBIOS over TCP/IP on all adapters
$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled }
foreach ($adapter in $adapters) {
$adapter.SetTcpipNetbios(2) # 2 = Disable NetBIOS over TCP/IP
}
Write-Host "[+] LLMNR and NetBIOS disabled."
Disable Built-in Administrator & Guest
The built-in Administrator (RID 500) account is a well-known target. It cannot be locked out by Account Lockout Policy, making it ideal for brute-force attacks. Rename it to something non-obvious and disable it if LAPS is managing local admin credentials.
# Disable the built-in Administrator account
Disable-LocalUser -Name "Administrator"
# Disable the Guest account
Disable-LocalUser -Name "Guest"
# Optionally rename Administrator to something non-obvious
Rename-LocalUser -Name "Administrator" -NewName "svcmgr"
RDP Hardening
If RDP must be enabled, harden it. Default port 3389 is scanned constantly. Network Level Authentication (NLA) forces authentication before a session is established, preventing unauthenticated pre-auth exploits.
# Enforce Network Level Authentication
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" `
-Name "UserAuthentication" -Value 1
# Change RDP port from default 3389 (security by obscurity — not a replacement for NLA)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" `
-Name "PortNumber" -Value 53389 # use any non-default port
# Restart Remote Desktop Services to apply
Restart-Service -Name "TermService" -Force
Secure Boot Certificate Update (June 2026)
This is one most people miss. In June 2026, many original Secure Boot signing certificates expire. If your system hasn't received the 2023+ certificate updates, Secure Boot may fail after that date. Verify you're on the updated certificates now.
# Check Secure Boot status
Confirm-SecureBootUEFI
# Check UEFI certificate database for updated 2023 certs
# Should return entries dated 2023 or later
Get-SecureBootPolicy
PowerShell Hardening
PowerShell is a double-edged sword. It's the most powerful management tool on Windows — and consequently, the most abused post-exploitation tool. It enables fileless malware, in-memory execution, AMSI bypasses, and living-off-the-land techniques that bypass most AV. Hardening it is non-negotiable.
Constrained Language Mode (CLM)
CLM restricts PowerShell to a limited subset of commands, blocking access to .NET types, COM objects, and Win32 API calls — exactly the things used in offensive scripts. It doesn't prevent all attacks, but it significantly raises the bar.
# Check current language mode
$ExecutionContext.SessionState.LanguageMode
# Should return: ConstrainedLanguage (when enforced via WDAC)
# CLM is enforced by WDAC policy — if WDAC is active, CLM activates automatically
# To test: try to use a .NET type in a session with CLM enforced
[System.Net.WebClient] # This should fail in CLM with "type not available" error
Script Block Logging — Event ID 4104
Script Block Logging records the actual PowerShell code that executes — including code that was obfuscated, downloaded from the internet, or dynamically generated at runtime. This is your primary forensic artifact for PowerShell-based attacks.
Computer Configuration
> Administrative Templates
> Windows Components
> Windows PowerShell
→ "Turn on PowerShell Script Block Logging" → Enabled
→ "Log script block invocation start / stop events" → Enabled (optional, verbose)
→ "Turn on Module Logging" → Enabled → Module Names: *
After enabling, monitor Event ID 4104 in the Microsoft-Windows-PowerShell/Operational log. Any script that looks obfuscated, base64-heavy, or invokes suspicious methods is worth investigating.
Remove PowerShell Version 2
PowerShell v2 does not support Script Block Logging, AMSI, or Constrained Language Mode. Attackers explicitly downgrade to v2 (powershell -version 2) to bypass all modern logging and security controls. Remove it.
# Remove PowerShell v2 engine (requires reboot)
Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root -NoRestart
# Verify it's gone — this should fail after removal
powershell -version 2 -command "Write-Host 'v2 still present'"
Conclusion
None of these controls in isolation makes a system secure. What they do — applied together — is force an attacker to work harder, make more noise, and burn more time. That's the goal. Security is about raising cost, not achieving invulnerability.
From a red team perspective: every one of these controls has a bypass. But a system with all of them configured correctly? That system is no longer the low-hanging fruit. It forces advanced tradecraft, which generates detectable artifacts, which is exactly what your blue team needs.
| Control | Category | What It Stops |
|---|---|---|
| BitLocker XTS-AES 256 | Storage | Physical access, cold boot, offline attacks |
| Kernel DMA Protection | Storage | PCIe/Thunderbolt DMA key extraction |
| Windows LAPS | Identity | Lateral movement via shared local admin password |
| UAC Always Notify | Identity | Silent privilege escalation via COM abuse |
| Account Lockout | Identity | Password spray and brute-force |
| Default-Deny Firewall | Network | Unsolicited inbound connections, C2 exfil |
| WDAC | Applications | Unsigned / untrusted code execution |
| ASR Rules | Applications | LSASS dumping, macro abuse, email payloads |
| Disable LLMNR/NetBIOS | Computer Mgmt | Responder hash capture, NTLM relay |
| PowerShell CLM | PowerShell | Win32 API abuse, .NET exploitation |
| Script Block Logging | PowerShell | Obfuscated/fileless malware (detection) |
| Remove PSv2 | PowerShell | Logging and CLM downgrade bypass |
// All configurations documented for educational and defensive purposes. Test in isolated environments before production deployment.