Ensuring your organization is secure has to start someplace. For most administrators this is a daunting task. Where do I start? What do I secure first? What would a Threat Actor look for? The sheer number of configuration capabilities in Windows Server and Windows 10 can make these questions hard to answer.
Ensuring your organization is secure has to start someplace. For most administrators, this is a daunting task. Where do I start? What do I secure first? What would a Threat Actor look for? The sheer number of configuration capabilities in Windows Server and Windows 10 can make these questions hard to answer.
This is where Microsoft Security Baselines come in. Microsoft has provided an industry-standard configuration that is broadly known and well-tested to use as a starting point. Different organizations will need different end settings, but starting with a well-known baseline can help jump-start your security stance.
The first step is to head over to the Microsoft Security Compliance Toolkit 1.0 page to download the tools.
At the time of writing this post the following baselines are available:
- Windows 10 Version 1507 up to 20H2
- Windows Server 2012 R2 up to 2019
- Microsoft 365 Apps for Enterprise
- Microsoft Edge
- Windows Update
When you follow the 'download the tools' link and then click Download, a list of baseline versions and tools are presented. Download only the version of baselines that you need. If the organization only has Windows 10 1909 then download 'Windows 10 Version 1909 and Windows Server Version 1909 Security Baseline.zip' when prompted.
Be sure to download PolicyAnalyzer.zip
This tool will become your best friend! The tool lets you load a GPO from a GPO Backup file and compare that GPO with any other GPO you've pulled in to the tool. This is useful to find changes between two versions of GPOs or Baseline levels.
Hint: If you edited a Baseline and need to find the settings you changed you can load a fresh copy of the baseline, your copy of the baseline and then look for the differences.
For the purposes of this article I will be using the latest 20H2 Baselines. The zip file will contain the following folders
|Documentation||Contains very important Documentation about the Baselines as well as the PolicyRules that are used by the PolicyAnalyzer. Can also include announcements from Microsoft.|
|GP Reports||Contains the GPO HTML Report for each policy|
|GPOs||Contains the actual Policies|
|Scripts||Scripts to Import the GPOs to AD, or Local|
|Templates||Contains GPO admx templates|
Understand the Baselines
I can't stress this enough! Understand the Baselines before applying them to your production environment. If you plop these Baselines in without proper testing and understanding I promise you things will break.
Read the Documentation
Your first task before doing anything else is to open the Documentation folder and review the Excel documents within. There are two documents, each shows different information. I'm using the 20H2 Baselines as an example, depending on your Baseline the names may be different.
'FINAL-MS Security Baseline Windows 10 and Windows Server v20H2.xlsx', contains ALL the baseline settings and their values. If you are implementing the baselines for the first time then you should review this document.
'New Settings in Windows 10 and Windows Server v20H2.xlsx', contains settings appearing in 20H2 that are different than the previous version of Baselines. If you have already implemented a previous version of baselines then you can review this document to see what settings have been added/changed or removed.
You can also read the GPO Report that we are all used to seeing in the Group Policy Management 'Details' tab by exploring the 'GP Reports' folder.
Microsoft has provided scripts to import these policies called 'Baseline-ADImport.ps1' and 'Baseline-LocalInstall.ps1' both of which are located in the Scripts folder.
Baseline-ADImport.ps1 - Imports all GPOs to Active Directory, these will show up under 'Group Policy Objects' and will not be applied to anything.
Baseline-LocalInstall.ps1 - Applies various GPO settings to the local machine based on which switch is passed.
-Win10DomainJoined - Windows 10, domain-joined -Win10NonDomainJoined - Windows 10, non-domain-joined -WSMember - Windows Server, domain-joined member server -WSNonDomainJoined - Windows Server, non-domain-joined -WSDomainController - Windows Server, domain controller
Test the Baselines
Testing is fairly simple. Create sub-OU's and apply the required Baselines to the OU. Move test machines and verify functionality. You can also use the Local import script to test a standalone machine without the risk of affecting any other machine on the domain.
Test your applications, test access to network resources, scan the machine with a vulnerability scanner, test remote access, test test test! Then test some more.
Once your testing is done then apply to a larger more varied group of computers and test some more!
It's inevitable, at some point you may need to link two separate Baselines to one OU. This commonly occurs during an upgrade of Windows from one build to a new build. An approach that I see often is to create an entirely new OU, disable inheritance, and then link all the GPOs that it should have to the new temporary OU. This approach leads to increased complexity and administrative effort.
WMI Filters are a good solution to the multiple baselines in one OU situation. WMI Filters can be used to target a specific build version of Windows 10. This lets you assign a WMI Filter to the MSFT Windows 10 [VERSION] - Computer GPO and only apply it to machines that match the build.
Create WMI Filter
You can use the Windows 10 - release information provided by Microsoft to determine the build number for 20H2, which is 19042.
- Open Group Policy Management and navigate to WMI Filters
- Right-click and select 'New'
- Provide Name/Description and click 'Add' and use the following information to build the query
Namespace: root\CIMv2 Query: SELECT * FROM Win32_OperatingSystem WHERE BuildNumber = "19042" AND ProductType = "1"
Creating a WMI Filter for a new version of Windows 10 is as easy as finding the new build number using the link provided and changing it in the query.
Note: ProductType = "1" limits the filter to client operating systems only.
- 1 = Client Operating Systems
- 2 = Domain Controllers
- 3 = Non-Domain Controller Server Operating Systems
Applying a WMI Filter
Once the Baselines are imported and the WMI Filter is created you can apply the filter by clicking on the MSFT GPO under 'Group Policy Objects' and picking the appropriate filter from the drop-down. Once the filter is in place you can see an overview by clicking on 'Group Policy Objects'
Currently, in my environment I have 2 Windows 10 2004 machines that I haven't upgraded, so my Workstations OU looks like this (I explain the Override GPO next). The use of WMI Filters ensures that my 2004 machines get only the 2004 Baselines and none of the new settings from the 20H2 Baselines, all without the need to recreate an entirely new OU and link a bunch of GPOs.
Editing the Baselines
Don't! Hear me out. Inevitably there will be a setting that you hate, and you want to turn it off. That is fine, this is your environment, tweak away BUT do not edit the Baseline.
Editing a Baseline causes so many Administrative headaches later on. Imagine this scenario, your organization wants to roll out the 20H2 update and all machines are 1909. The 1909 Baselines are applied in the proper locations, but they have been edited and settings changed. When you go to apply the 20H2 Baselines you will need to find which 1909 settings had been changed and carry those changes forward to the 20H2 Baselines.
As someone who has had to go find these differences, I can say it's not fun. Even when using the Policy Analyzer Tool it takes time.
Overrides to the Rescue!
A great approach to combat the need to make a change and the desire to keep the Baselines at baseline is to use an Override GPO. This override GPO can be set to the highest precedence on the OU and you can override baseline settings by negating the baseline defined setting.
For example, the 20H2 Baseline has a setting for Remote Desktop Connection Client that sets 'Do not allow passwords to be saved' to Enabled. Well I hate it...I hate it so much on my internal domain that I want to turn it off. I research the setting and learn that Unconfigured and Disabled provide the same behavior.
Using this information I can create an override that configures the 'Do not allow passwords to be saved' setting to 'Disabled'. When I apply the Override GPO I will set it at a higher precedence than either of the MSFT Windows 10 - Computer baselines. This ensures that my settings are applied and not the conflicting settings in the Baseline.
The below image is of my 'Workstations' OU. I have applied both 'MSFT Windows 10 20H2 - Computer' and 'MSFT Windows 10 2004 - Computer' because I have not upgraded all my workstations yet. A WMI filter applies the correct MSFT Windows 10 - Computer policy based on build number.
Right now any computer in Workstation OU that is either Windows 10 20H2 or Windows 10 2004 will get the raw Baselines applied. This also means they get the setting I hate enabled.
I have created my Override and adjusted the settings to my liking. Now my Workstations OU looks like so
Notice the 'Link Order', the 'SEC C - MSFT Windows 10 Overrides' has higher precedence than either of the MSFT Baselines so my 'Disabled' setting takes precedence over the 'Enabled' setting defined in the Baselines.
The Override GPO doesn't need to be versioned as 20H2 or 2004 because it doesn't matter. Even if a setting we overrode was removed in 20H2 and was set back to defaults our override would still ensure that the value we want is used. Same logic for a 2004 computer. If the 2004 Baseline did not enable the 'Do not allow passwords to be saved' setting then it still doesn't matter, our override is ensuring that setting will now and forever be disabled as long as the override exists and has precedence.
I currently have three override policies in place on my internal domain, you can override any Baseline this way. For example:
As you can see, now when we implement new Baselines for a new version of Windows we simply link the Baseline and ensure it's below our Override GPO. No more Administrative overhead of trying to remember what was changed, doing comparisons or carrying settings over. A great side effect of using Override GPOs is that you have documented your deviations from the Microsoft Security Baselines.
Good Luck on your adventure in implementing the Microsoft Security Baselines! Remember, these baselines aren't the end-all-be-all to securing your environment. They are simply a good starting point, you will need to test, then test some more and then tweak and when you tweak I hope you now see the value of using Override GPOs. Work smarter not harder!