In this article you will find my settings for hardening Windows Server 2022. These settings can be used for the template for VMs. New VMs based on these settings therefore already have a certain level of security. In my opinion, the settings are not too restrictive and should therefore be suitable for most applications/services.
I have installed a Windows Server 2022 Standard (with desktop) for hardening. This article starts directly after the installation of the operating system. Apart from the necessary drivers and tools for the hypervisor, no other software is installed.
After installing the operating system, only the absolutely necessary software should be installed (e.g. drivers for the hardware or VM tools), naturally in the latest version. Additional software that is only for your own convenience, such as other browsers or editors, has no place on a server.
Install Windows updates
The first updates can be installed immediately after installing the operating system. If you have not already done so, you can also think about patch management at this point.
Updates must be installed promptly, not only for the operating system, but also for other software that is installed on the server.
Deactivate or rename local administrator
It is best to create a new local administrator account and deactivate the existing "Administrator" account. The background to this is that the SID of the local administrator starts with "S-1-5" and ends with "-500". This makes it very easy to determine the name of an unnamed administrator account:
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine, $env:computername)
$UserPrincipal = New-Object System.DirectoryServices.AccountManagement.UserPrincipal($PrincipalContext)
$Searcher = New-Object System.DirectoryServices.AccountManagement.PrincipalSearcher
$Searcher.QueryFilter = $UserPrincipal
$Searcher.FindAll() | Where-Object {$_.Sid -Like "*-500"} | Select-Object SamAccountName,Sid
The better option is to create a new administrator account and deactivate the "Administrator" account. If you want to be on the safe side, deactivate the local administrator account, rename it and create a new account for the administration.
Deactivate automatic start of the Server Manager
Deactivating the Server Manager is more of a cosmetic nature, I personally find it awful when programs start automatically after logging in. The Server Manager in particular starts quite slowly and causes a relatively high CPU load for a short time, which doesn't have to be the case every time you log on to the server, especially if you rarely or never use the Server Manager:
To prevent the Server Manager from starting at every login, the task for the Server Manager can be deactivated in the Task Scheduler:
Deactivating the task also deactivates the automatic start of the Server Manager for other users who log on to the server.
Deactivate services that are not required
Windows Server 2022 comes with some services that are not required for most servers. Some of the services are started automatically, some are only started when required or cyclically by the operating system. A good example is the "Print Spooler", this service is active on every server, even if the server neither serves as a print server nor has to print to printers itself. However, the "Print Spooler" in particular caused considerable security gaps with the "PrintNightmare" vulnerability.
Services that are not required should therefore be deactivated. The following PowerShell script provides all services that are usually not required:
$Services = @(
"InstallService",
"Spooler",
"WPDBusEnum",
"fdPHost",
"ShellHWDetection",
"TrkWks",
"bthserv",
"NcbService",
"SensrSvc",
"WiaRpc",
"upnphost",
"AudioEndpointBuilder",
"FrameServer"
)
foreach ($Service in $Services) {
Get-Service $Service | select Name,Displayname,StartType,Status
}
The services can be checked using the script above. If the services are not required, they can be deactivated with the following script:
$Services = @(
"InstallService",
"Spooler",
"WPDBusEnum",
"fdPHost",
"ShellHWDetection",
"TrkWks",
"bthserv",
"NcbService",
"SensrSvc",
"WiaRpc",
"upnphost",
"AudioEndpointBuilder",
"FrameServer"
)
foreach ($Service in $Services) {
Get-Service $Service | Set-Service -StartupType Disabled
}
If a service is needed after all, it can be reactivated via group policy or manually. The spooler service is a good example of this: By default, it should always be deactivated and only reactivated if required.
Uninstall Internet Explorer / Edge
Two browsers are pre-installed in Windows Server 2022: Internet Explorer and Edge. In my opinion, you don't need a browser on a standard server, so at least Internet Explorer should be uninstalled.
Internet Explorer will not receive any security updates from July 2022 and should therefore be uninstalled:
dism /online /Remove-Capability /CapabilityName:Browser.InternetExplorer~~~~0.0.11.0
Edge is also pre-installed on Windows Server 2022, but can also be uninstalled:
The less software is installed on a server, the smaller the attack surface. Of course, it is convenient if a browser is installed and links in error messages can be opened directly.
If it is absolutely necessary, a browser can be reinstalled later if required and provided directly with a policy (see section "Edge Security Baseline").
Apply Windows Security Baseline
With the "Microsoft Security Compliance Toolkit", Microsoft offers a set of settings that increase the security of the operating system. The recommended settings are easy to apply and can also be granularly withdrawn or extended if required. The Security Compliance Toolkit can be downloaded here:
At least the following two components are required from the download:
- LGPO.zip
- Windows Server 2022 Security Baseline.zip
With LGPO, the recommended security settings can be transferred to a local group policy. The local group policy has the advantage that it is always applied, regardless of whether the server later joins an Active Directory or remains a stand-alone server. The local group policies can also be overwritten with domain group policies if necessary. This means that a certain level of security can always be enforced for the operating system, even if it is just a test system that may not apply a group policy from the AD.
However, the security settings from the Security Compliance Toolkit can also be transferred to a group policy for the domain. Whether the settings are made locally or in the domain can therefore be freely selected.
To apply the settings locally, the LGPO tool must be copied to the "\Scripts\Tools" subfolder:
The policies can then be imported using PowerShell and the following command:
.\Baseline-LocalInstall.ps1 -WSMember
The "WSMember" parameter specifies which set of policies is to be imported. The following specifications are possible:
- WSMember - Windows Server, domain-joined member server
- WSNonDomainJoined - Windows Server, non-domain-joined
- WSDomainController - Windows Server, domain controller
WSMember is therefore suitable for most servers.
Tip: For VMs, the following error may occur when applying the local GPO after applying the security baseline:
C:\Windows\system32>gpupdate /force
Updating policy...Computer Policy update has completed successfully.
The following warnings were encountered during computer policy processing:
Windows failed to apply the {F312195E-3D9D-447A-A3F5-08DFFA24735E} settings. {F312195E-3D9D-447A-A3F5-08DFFA24735E} settings might have its own log file. Please click on the "More information" link.
User Policy update has completed successfully.For more detailed information, review the event log or run GPRESULT /H GPReport.html from the command line to access information about Group Policy results.
The problem here is the settings for "Device Guard" or "Virtualization Based Security" from the security baseline. These settings may not be available within a VM or must first be activated for the VM. The settings for ESXi 7 can be found under the following link:
If Virtualization Based Security (VBS) is not supported by the hypervisor, the following settings must be changed in the local GPO:
Apply Edge Security Baseline
There is also a security baseline for the Edge browser, which can also be found in the Microsoft Security Compliance Toolkit. If the Edge browser is installed, the policy can also be used to apply a few important settings for Edge directly. Here, too, it is possible to apply the security settings locally or via GPO.
For a local policy, the LGPO tool must again be copied to the "Scripts\Tools" subfolder. The local policy can then be applied again with ".\Baseline-LocalInstall.ps1" (without parameters).
Configure Windows Firewall
The Windows Firewall also contains some activated rules that are not necessarily required on a standard server. Incoming 64 rules are active:
There are even 75 outgoing rules, although the Windows Firewall allows all outgoing connections by default.
By default, the Windows Firewall only allows connections that are permitted by a rule. Outgoing connections (from the local server to other destinations) are allowed by default and only blocked if there is a corresponding rule.
The firewall rules can be thinned out somewhat with the following PowerShell script:
$FirewallRules = @(
"AllJoyn Router (TCP-In)",
"AllJoyn Router (TCP-Out)",
"AllJoyn Router (UDP-In)",
"AllJoyn Router (UDP-Out)",
"Captive Portal Flow",
"Cast to Device functionality (qWave-TCP-In)",
"Cast to Device functionality (qWave-TCP-Out)",
"Cast to Device functionality (qWave-UDP-In)",
"Cast to Device functionality (qWave-UDP-Out)",
"Cast to Device SSDP Discovery (UDP-In)",
"Cast to Device streaming server (HTTP-Streaming-In)",
"Cast to Device streaming server (RTCP-Streaming-In)",
"Cast to Device streaming server (RTP streaming out)",
"Cast to Device streaming server (RTSP-Streaming-In)",
"Cast to Device UPnP Events (TCP-In)",
"Connected User Experiences and Telemetry",
"Desktop App Web Viewer",
"DIAL protocol server (HTTP-In)",
"Email and accounts",
"mDNS (UDP-In)",
"mDNS (UDP-Out)",
"Microsoft Media Foundation Network Source IN [TCP 554]",
"Microsoft Media Foundation Network Source IN [UDP 5004-5009]",
"Microsoft Media Foundation Network Source OUT [TCP ALL]",
"Narrator",
"Start",
"Windows Default Lock Screen",
"Windows Feature Experience Pack",
"Work or school account",
"Your account"
)
foreach ($FirewallRule in $FirewallRules) {
Get-NetFirewallRule -Displayname $FirewallRule | Set-NetFirewallRule -Enabled:false
}
The script deactivates the corresponding rules, but does not delete them. In my opinion, it also makes sense to prohibit outgoing RDP connections from the server to other destinations, as this provides some protection against the server being used as a "jump server" to other servers. However, it only protects a little, as anyone with administrator rights on the server can simply deactivate these firewall rules again. The firewall rules therefore belong in a domain group policy. If you still want to create a corresponding firewall rule to block outgoing RDP connections, you can use the following command:
New-NetFirewallRule -DisplayName "Block Outgoing Remote Desktop Connection" -Direction Outbound -Program "%windir%\system32\mstsc.exe" -Action Block -Description "Block outgoing RDP Sessions by mstsc.exe"