Despite an abundance of “building your own lab” articles available online, there really is only one collection of articles that document Windows Defender Application Control (Device Guard), hereby referred to as WDAC: Matt Graeber’s Exploit Monday posts on the topic. I dove into playing with WDAC a year back while developing WMImplant, and I quickly realized that there is pretty limited amount of documentation on the topic. Microsoft does have a few articles about WDAC, but I ran into issues and the information available didn’t help to solve my problems. I want to help share how I created a lab with a small number of machines and deployed WDAC for testing purposes.
One thing to note with WDAC – a code integrity policy can only be created on Windows 10 Enterprise and Server 2016 (although it can be applied on non-enterprise versions of Windows 10), so your lab will need either (or both) VMs. Now, let’s start with some basic terminology or info that will be referenced throughout my upcoming WDAC posts. A lot of this is documented extremely well in Matt’s posts, so just to sum them up:
- Code Integrity Policy – A code integrity policy is a file containing the different rules that Device Guard will enforce on your system(s). A code integrity policy is originally an XML file, which contains the rules that are enforced on your system. The XML file is converted into a binary format (.p7b) which is the format that Windows uses to process the code integrity policy.
- Event Log Information
- The Microsoft-Windows-DeviceGuard/Operational Event log is used to monitor if your policy was successfully processed (or any errors while attempt to do so)
- The Microsoft-Windows-CodeIntegrity/Operational Event Log is used to audit applications that attempted to run which were blocked by your code integrity policy
Note: Prior to creating your code integrity policy, you will want to install all the software you want running within your virtual machine. Any new software after you create the code integrity will essentially require an update to your code integrity policy.
To create a code integrity policy, you will need to start a command prompt with Administrative permissions on your Windows 10 (or Server 2016) system and start PowerShell. The cmdlet that you will use to create a code integrity policy is New-CIPolicy. When creating a policy, we will need to specify the level of enforcement that we want WDAC to perform. This page describes the different levels available when creating a code integrity policy. In this instance, we are going to enforce it at the PCACertificate level. The PCACertificate is generally the highest available certificate in the certificate chain, and one below the root level certificate. Using the PCACertificate level will allow some flexibility between a secure policy and code integrity policy management (not needing to update the code integrity policy with every single update to a signed application). Additionally, we’re going to provide the -UserPEs flag to include user-level executables in the code integrity policy. Without the -UserPEs flag, the code integrity policy would only have rules for kernel level binaries. The exact command that you should run is:
New-CIPolicy -Level PCACertificate -UserPEs -FilePath C:\Windows\System32\CodeIntegrity\Initial.xml
You should see something similar to the following:
As the message states, this will take a while and can take many hours to complete, so be prepared to wait.
After you have generated your code integrity policy, you can easily view the Initial.xml file in any text editor. It will likely look something similar to the following:
The biggest item to note in this policy is the first red box which is circling the “Enabled: Audit Mode” rule. By default, when you create a code integrity policy, your rules will have Audit Mode enabled (more on this later). The next step is to use the ConvertFrom-CIPolicy cmdlet to convert your XML based rules into a binary format that Windows will parse. The command you should run is:
ConvertFrom-CIPolicy -XmlFilePath C:\Windows\System32\CodeIntegrity\Initial.xml -BinaryFilePath C:\Windows\System32\CodeIntegrity\SIPolicy.p7b
The path C:\Windows\System32\CodeIntegrity\CIPolicy.p7b is used because that is one of the locations that Windows 10 will expect the code integrity policy to be by default (the other is the EFI System partition/Microsoft/Boot). To deploy our code integrity policy, I will use group policy that’s enforced at the domain controller. To do this, I’m going to copy the SIPolicy.p7b file to my domain controller and set up a file share. In this case, I’m creating a folder called DGFiles on the root of C:\, and copying the SIPolicy.p7b file into it. I’ve set the share permissions to be read-only for Domain Computers (please note, there are likely better ways to distribute this in an enterprise environment, this is for ease of use in a lab):
Next, I’m modifying the “Default Domain Policy” to enable WDAC and I’m providing the path to the SIPolicy.p7b file. To enable the policy, you can find it in Computer Configuration – Policies – Administrative Templates – System – Device Guard. From here, edit the policy to include the path to the policy at \\<DOMAINCONTROLLER>\DGFiles\SIPolicy.p7b, as shown in the image below.
Now that this is applied at the domain controller, you can reboot your Windows 10 workstation. After rebooting, you can confirm if the policy has been applied to your workstation via two different means. One method is that you should see the SIPolicy.p7b file copied back into your local system’s C:\Windows\System32\CodeIntegrity\SIPolicy.p7b location. However, a better method is the event log. If you access the Event log and browse to the Applications and Services Logs – Microsoft – Windows – Device Guard – Operational log. Within it, you should see an event ID of 7010 and see that your policy has been successfully processed, similar to the image below.
At this point, the policy should be applied to your system. In the event that you are running into any issues, try rebooting once. As I mentioned near the beginning of this post, our code integrity policy is currently in audit mode. Audit mode will not block any applications from running, even if they are untrusted according to your code integrity policy. Audit mode will log any application that should have been blocked within the Microsoft-Windows-Code Integrity/Operational event log. For example, I downloaded kitty.exe (the SSH client), after I’ve already created the code integrity, therefore kitty.exe should not be allowed to run on my system. However, due to audit mode, when I try to run kitty.exe, it is allowed to run, but it documented in the event log, similar to the image below.
At this point, you have Windows Defender Application Control successfully deployed to your system and currently auditing the applications that are running. An error that I did encounter prior to figuring out the cause was within the Device Guard – Operational Event Log and an event ID of 7011 stating that the policy could not be processed because it was being used by another process, similar to below.
I finally determined that I received this error by having two different policies trying to access the file at the same time (makes sense… right?). What I found was I had a local group policy configuration enabling WDAC in addition to a domain group policy enabling it. This resulted in the above error and the policy not being applied to my system.
In my opinion, Windows Defender Application Control (Device Guard) is an excellent defensive technology that can be used to reduce the attack surface within an organization. For attackers or researchers also looking to identify unique application whitelisting bypasses, WDAC should be the bar that is used to measure effectiveness. A WDAC bypass allowing arbitrary code execution would be highly valuable and is very likely to bypass other defensive technologies used across the industry.
In upcoming posts, we’ll look to merge the initial code integrity policy with the results from the Code Integrity log that might have been missed while creating the initial code integrity policy. I hope that this helps understand how to setup a basic lab with WDAC, and if you have any questions, please don’t hesitate to contact us at FortyNorth Security.
A big think you to Matt Graeber (@mattifestation) for reviewing this blog post!