Windows Defender Application Control (WDAC) Updates in 20H2 and Building a Simple, Secure Windows-only Policy

Until recently, I had gotten away from configuring Windows Defender Application Control (WDAC) until the lead-up to Christmas when I wanted to repurpose an older Microsoft Surface Gen. 1 Laptop as my young daughter’s first Windows-based computer for play and experimentation.

As a security practitioner, obviously, I want to protect her from external threats as much a possible but as a dad who is acutely aware and in awe of a child’s willingness to experiment, I acknowledge that my daughter will do everything in her power to corrupt (intentionally or otherwise) her Windows installation. Along with traditional least-privilege principles in place, WDAC, with a proper policy in place should serve as an ideal, built-in solution to both help protect her from external threats but to also mitigate self-inflicted destruction. 😉

The goal of this post is to highlight some of the awesome WDAC improvements made since the release of Windows 10 20H2 in the context of building and applying a relatively simple but very secure policy to a single system. My hope is to help supply further evidence that WDAC is worthy of your consideration if mitigating and detecting large classes of attack techniques is a priority for you and/or if you’re a parent wanting to squeeze as much shelf life out of a Windows computer for your kids.

Latest Improvements to WDAC in 20H2

Before diving into the weeds, I wanted to highlight the improvements to WDAC in 20H2 that I observed.

  1. There are no longer SKU licensing restrictions when building WDAC policies. Previously, one needed Window 10 Enterprise or Education to configure and build WDAC policies. This restriction has since been lifted. The policy described below was built and deployed on a Windows 10 Professional host.

My WDAC Policy Objective

Build a secure, Windows-only policy that just works.

This objective sounds nice but warrants additional explanation:

  • “Secure”: When I refer to secure, I am referring to a policy that is not overly permissive and wouldn’t present any immediately obvious bypasses. I would prefer that my policy not have any rules that would implicitly permit execution of something outside the scope of the policy, in this case, “Windows-only.” For example, if at all possible, I always try to avoid FilePath rules as those can be prone to introducing unintentional bypasses if an attacker is able to drop an executable or script into a permitted directory.

Laptop Specifications

When working with WDAC, it is important to consider not only the software you intend to permit but to also be mindful of its hardware since that can affect both kernel and user-mode rules for 3rd-party drivers and relevant, accompanying software.

  • Laptop: Microsoft Surface Gen. 1 Laptop

This specification affords a unique privilege in that in theory, with both the hardware and software all being Microsoft, I should be able to get away with a minimal WDAC policy that conforms to my scope of Windows and Microsoft-Store-signed only. I’ve had mixed results in the past but as you will see in this post, 20H2 and general improvements to signing practices at Microsoft permit extremely simple and secure WDAC policies for 1st-party Microsoft hardware.

Another challenge that would have been previously imposed was that building WDAC policies used to only be possible on Windows 10 Enterprise systems. That licensing restriction has since been lifted which will permit building and deploying a policy without issue on this Windows 10 Professional build.

Building and Deploying a Custom Windows-only Policy

For this simple policy, I modified and then merged two separate policies:

  1. The DefaultWindows_Audit.xml template policy located in C:\Windows\schemas\CodeIntegrity\ExamplePolicies. I copy and rename this policy as BasePolicyWindows.xml in this post.

I made the following modifications to DefaultWindows_Audit.xml:

  1. I added the “Disabled:Flight Signing” rule. I have no intention to run Windows Insider Preview (WIP) builds, therefore flight-signed code (i.e. code specially signed for WIP builds) should not be permitted to execute.

I am a huge fan of the DefaultWindows_Audit.xml template policy supplied by Microsoft as it allows Windows (excluding 3rd-party software) in-box kernel and user-mode code to boot, execute, and update without issue. Regardless of the WDAC policy I’m building, I almost always use DefaultWindows_Audit.xml as my baseline policy upon which additional rules are added/merged.

Next, I made the following modifications to the Microsoft recommended block rules:

  1. I removed all the policy rules. Since I will merge these rules into a base policy, I like to minimize confusion by maintaining policy rules in a single base policy, BasePolicyWindows.xml in this case.

Finally, I merged and deployed my policy using the following PowerShell cmdlets:

I then rebooted and ran the Windows build through its courses in audit mode to find no surprises. I then placed WDAC into enforcement mode by removing the “Enabled:Audit Mode” rule and since my daughter has been using it, I’ve been monitoring CodeIntegrity event log events and thus far, I only get block events for Microsoft.Build.dll and Microsoft.Build.Framework.dll being loaded by mscorsvw.exe. Both of these rules are present in the Microsoft recommended block rules added as the result of Jimmy’s findings here.

There are additional steps that could be taken to further secure the integrity of the deployed WDAC policy against a rogue admin (e.g. policy signing and UEFI policy protection) but I don’t feel they are relevant to this post.

When all was said and done, this whole process of building a policy, auditing it, placing it into enforcement mode and performing follow-on monitoring took just over an hour.

Conclusion

My hope is that any security practitioner who is comfortable with Windows at least experiment with WDAC. As a defender who’s professional work involves helping to develop detection logic for attack technique after attack technique, I sometimes feel defeated at the notion and expectation that every attack technique should be detected, a reality that is far from realistic or achievable in many cases. Knowing what I know about the strength of WDAC enforcement, I have direct experience in working within a reality where the majority of attack techniques are almost completely mitigated by enforcing code integrity.

Again for reference, here are the modified/generated policy files I used on my daughter’s laptop: https://gist.github.com/mattifestation/425b2c8a3b5a9b74d6938394019cc177

Security Researcher, SpecterOps