-
Notifications
You must be signed in to change notification settings - Fork 164
WDAC Notes
- WDAC stands for Windows Defender Application Control
- It's used for Application and File whitelisting in Windows.
We have to make sure the WDAC policy that we are going to use as a supplemental policy has PolicyType="Supplemental Policy"
in the SiPolicy
element of the XML file. If it doesn't, then we have to use this command to change it from base policy to supplemental policy of our base policy.
That will also change/create the <BasePolicyID>GUID</BasePolicyID>
element in the supplemental policy XML file. The GUID will be the PolicyID
of the base policy specified in the command.
We have to make sure that the supplemental policy does not contain any policy rule options that only work with a base policy. This chart shows which ones can be used in a supplemental policy.
You can use this PowerShell code to automatically make sure non-supplemental policy rule options don't exist in a supplemental policy XML file:
$supplementalPolicyPath = ".\Supplemental_Policy.xml"
@(0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 15, 16, 17, 19, 20) | ForEach-Object {
Set-RuleOption -FilePath $supplementalPolicyPath -Option $_ -Delete
}
A supplemental policy can only have these policy rule options:
- 5 Enabled:Inherit Default Policy
- 6 Enabled:Unsigned System Integrity Policy (Default)
- 7 Allowed:Debug Policy Augmented
- 13 Enabled:Managed Installer
- 14 Enabled:Intelligent Security Graph Authorization
- 18 Disabled:Runtime FilePath Rule Protection
Deny rules are ignored in supplemental policies by WDAC engine. Supplemental policies are only meant to expand what the base policy trusts, that's why only allow rules are supported in supplemental policies, and that's also the reason why we don't need to merge Microsoft recommended block rules or driver block rules with a supplemental policy.
When the base policy has a deny rule for a file and we allow the same file in a supplemental policy, the file will still be blocked, because explicit deny rules have the highest priority.
Suppose you have a base policy and this base policy will have supplemental policies later on. To add the details of the code signing certificate to the base policy in order to get it ready for signing, you need to use the -Supplemental
switch parameter with the Add-SignerRule cmdlet. If you don't do that, the signed base policy after deployment won't accept any signed supplemental policies. The -Supplemental
parameter can only be used for a base policy.
- Using
-Supplemental
parameter withAdd-SignerRule
cmdlet on a Supplemental policy will cause boot failure after deploying it, because that parameter should only be used when adding signer rules to a base policy.
Whether the deployed supplemental policy is unsigned or signed, you can remove it just like any unsigned policy using CITool.
If you deploy an unsigned supplemental policy on a system where all policies including base and supplemental, are signed, the deployed unsigned supplemental policy will be ignored.
First, Block/Deny File rules are specified in <FileRules>
element which is directly under <SiPolicy>
element in the XML file. Deny rules are created by having <Deny ID="ID_DENY_"
at the beginning of their lines. For example:
<Deny ID="ID_DENY_AGENT64_SHA1" FriendlyName=<Textual Description/Name> Hash=<Hash Numbers> />
Second, there are File Reference rules for each Deny rule that only mentions them by ID, and these are exactly the same as Allow rules because only Rule IDs are mentioned and nothing about the nature of the rule itself. These are in:
<SiPolicy>
<SigningScenarios>
<SigningScenario>
<ProductSigners>
<FileRulesRef>
<FileRuleRef RuleID="<The same ID of the Deny File rule mentioned earlier>" />
</FileRulesRef>
</ProductSigners>
</SigningScenario>
</SigningScenarios>
</SiPolicy>
Denied certificates/signers are first mentioned in <SiPolicy
=> <Signers>
with the following syntax:
<Signer ID="ID_SIGNER_VERISIGN_2010" Name="VeriSign Class 3 Code Signing 2010 CA">
... Other possible attributes ...
</Signer>
Unlike file rules, this first part doesn't specify whether the certificate/signer must be allowed or blocked by the WDAC policy.
In order to specify whether a certificate/signer should be denied/allowed, the ID of each signer must be specified in the second part of the XML policy file in <DeniedSigners>
element:
<SigningScenarios>
<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_<Some generic String>" FriendlyName="<Name>">
<ProductSigners>
<DeniedSigners>
<DeniedSigner SignerId="<ID of the Signer mentioned above in the <Signers> section>" />
</DeniedSigners>
</ProductSigners>
</SigningScenario>
</SigningScenarios>
Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard | select -Property *codeintegrity* | fl
2
means Enforced, 1
means Audit mode, 0
means Disabled/Not running.
- Windows Defender Application Control Policy (Kernel Mode)
- Windows Defender Application Control User Mode Policy (User Mode)
CITool --refresh
Old Method: using RefreshPolicy(AMD64).exe
Using RefreshPolicy(AMD64).exe only works when you add a new policy to the Windows folder, but when you delete a policy from that folder, running RefreshPolicy(AMD64).exe won't make the apps that were previously allowed to run by the policy we just deleted, to be blocked from running again. so after we remove a policy from Windows folder, a system restart is required.
This makes sense because apps that have been previously allowed to run by a policy that we just deleted might be still running in the background or even foreground, so to properly stop them, just running RefreshPolicy(AMD64).exe
isn't enough and data loss could've occurred if that was the case.
It consists of 2 elements:
This one contains the Certificates/Signers of the Kernel-mode drivers
<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS_1" FriendlyName="Driver Signing Scenarios">
And this one contains the Certificates/Signers of the User-mode binaries
<SigningScenario Value="12" ID="ID_SIGNINGSCENARIO_WINDOWS" FriendlyName="User Mode Signing Scenarios">
Only the Value
needs to stay the same. So, for Kernel-mode drivers it should always be 131 and for User-mode binaries it should always be 12, anything else can be customized.
Merge-cipolicy
cmdlet does not include duplicates, neither duplicate rules nor rules with duplicate file hashes.
WDAC forces Allow-list architecture by nature, not deny-list architecture. An empty deployed policy allows nothing to run and leads to system failure. This is why Microsoft recommended blocklists include 2 Allow All rules with the Deny rules, that changes the WDAC policy's nature from being an Allow-list to being a Deny-list.
From Microsoft recommended block rules document, copy the WDAC policy XML at the end (you might need to expand that section to view it), use a text editor like VS Code to edit it as recommended:
The blocklist policy includes "Allow all" rules for both kernel and user mode files that make it safe to deploy as a standalone WDAC policy. We can even deploy it side-by-side with AllowMicrosoft policy, by keeping its allow all rules in place. Refer to this document about how multiple base policies work.
"Only applications allowed by both policies (All Base policies) run without generating block events", that means even though the Microsoft recommended block rules have 2 allow all rules, they don't actually allow everything to run, because the same allow all rules don't exist in the default AllowMicrosoft policy, it only contains explicit allow rules.
On Windows versions 1903 and above, Microsoft recommends converting this policy to multiple policy format using the Set-CiPolicyIdInfo
cmdlet with the -ResetPolicyId
switch. Then, you can deploy it as a Base policy side-by-side with any other policies in your environment.
If merging into an existing policy that includes an explicit allowlist, you should first remove the two "Allow all" rules and their corresponding FileRuleRefs:
<Allow ID="ID_ALLOW_A_1" FriendlyName="Allow Kernel Drivers" FileName="*" />
<Allow ID="ID_ALLOW_A_2" FriendlyName="Allow User mode components" FileName="*" />
<FileRuleRef RuleID="ID_ALLOW_A_1" />
<FileRuleRef RuleID="ID_ALLOW_A_2" />
-
Deploying Microsoft recommended block rules (Driver or user mode) alone, after removing the allow all rules from them, will cause boot failure, for obvious reasons.
-
How to check the version of Microsoft recommended driver block rules that are being enforced
- The version is mentioned in Code Integrity operational event logs with an event ID of
3099
in the General tab.
- The version is mentioned in Code Integrity operational event logs with an event ID of
-
We don't need to use the Recommended Kernel Block Rules in WDAC when creating a policy because it's already being enforced by default and if we want to update it more regularly, we can do so by following this section of the document. Or by Fast and Automatic Microsoft Recommended Driver Block Rules updates.
Citation: If you only manage Windows 11 22H2 systems (and above), then you don't need the recommended driver block rules in your WDAC policy. Otherwise, you should have the driver block rules in your policy. In either scenario, you should have the recommended user mode rules.
Citation: ISG does not include the recommended blocklist(s).
Citation: About deploying new Signed WDAC policies rebootlessly using CITool.
-
Set the hypervisor Code Integrity option for the WDAC policy XML file to Strict only after using
Add-SignerRule
cmdlet, because after runningAdd-SignerRule
cmdlet, the<HvciOptions>
resets to0
. -
Using Signtool.exe with
-fd certHash
will default to the algorithm used on the signing certificate. For example, if the certificate hasSHA512
hashing algorithm, the file that is being signed will use the same algorithm. -
Sometimes New-CIPolicy Cmdlet creates 2 file rules for each driver file, such as
.sys
files. One of them is stored in Driver signing scenarios section under<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS_1" FriendlyName="">
and the other is stored in User mode signing scenarios section under<SigningScenario Value="12" ID="ID_SIGNINGSCENARIO_WINDOWS" FriendlyName="">
. More info here -
File rule levels and Cmdlets like New-CiPolicy only create rules for files with supported extensions. The table in this page lists all of the support file extensions.
$Package = Get-AppXPackage -Name "Microsoft.WindowsStore"
$Rules += New-CIPolicyRule -Package $Package -Deny
New-CIPolicy -FilePath ".\store.xml" -Rules $Rules
Removing these shouldn't cause any problem as long as you are using stable OS version
# Flight root Certs removal
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_STORE_FLIGHT_ROOT"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_WINDOWS_FLIGHT_ROOT"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_ELAM_FLIGHT"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_HAL_FLIGHT"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_WHQL_FLIGHT_SHA2"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_WINDOWS_FLIGHT_ROOT_USER"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_ELAM_FLIGHT_USER"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_HAL_FLIGHT_USER"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_WHQL_FLIGHT_SHA2_USER"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_RT_FLIGHT"
Starting with Windows 11 22H2, CITool is available in Windows by default and Refresh tool is no longer needed, so use the commands below to remove the certificates that allow that tool to be executed, their order of execution is important.
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_SIGNER_MICROSOFT_REFRESH_POLICY"
Remove-CIPolicyRule -FilePath "DefaultWindows_Enforced.xml" -Id "ID_FILEATTRIB_REFRESH_POLICY"
Questionable software such as pirated software are never recommended to be allowed in the WDAC policy because they are tampered with. Pirated software can have signed files too, but they are modified and as a result there is a mismatch between the file hash and the hash of the file saved in their digital signature. When such a mismatch exists for signed files, Authenticode reports the mismatch, and the file can't be allowed in a WDAC policy.
If you want to go through many files and see which ones have a mismatch between their file hash and signature hash, you can use the following PowerShell (core) command, it searches through a folder and all of its sub-folders quickly using parallel operations:
Get-ChildItem -Recurse -Path "Path\To\a\Folder" -File | ForEach-Object -Parallel {Get-AuthenticodeSignature -FilePath $_.FullName} | Where-Object {$_.Status -eq 'HashMismatch'}
The limit as stated in the official document is 32 active policies on a device at once. That is the total number of Base policies + Supplemental policies + any active system deployed policies.
If you've deployed a Signed WDAC policy on a system and then decide to reset it, either using local install or cloud download, it will fail during the reset process. You must remove the signed WDAC policy prior to performing the reset.
Unsigned WDAC policies don't have this behavior. Since they are neither cryptographically signed nor tamper-proof, they will be removed during the reset process and after reset the system will not have the WDAC policy.
This behavior is true for Lightly managed, Allow Microsoft and Default Windows WDAC policy types.
Normally, .cip
files would have to have the same name as the GUID of the xml file they were converted from, but that's no longer necessary. Using CiTool in Windows 11 build 22621
, they can be deployed with any name, even without a name, and lead to a successful WDAC policy deployment.
If a base policy has rule option number 8, Required:EV Signers, it will require all kernel-mode drivers to have EV signer certificates. You cannot bypass this requirement with a Supplemental policy, you cannot allowlist non-EV signed files in any way. Non-EV signed files will be blocked even if the base policy is in Audit mode. This is true for any type of base policy such as Default Windows, Allow Microsoft, Strict Kernel mode etc.
-
Enabled:Dynamic Code Security (generation)
-
Required:Enforce Store Applications
When we remove the SigningScenario Value="12"
completely which is responsible for User Mode code integrity in the xml policy and also remove any signers that belong to User mode section, such as those that have _user
in their ID, the Merge-CIPolicy cmdlet automatically removes EKUs that belong to the policy rule options mentioned above during a merge.
Removing the User mode signers, rules and Enabled:UMCI
rule option allows us to create a Kernel-only WDAC policy that doesn't touch User mode binaries/drivers.
For a Kernel-mode only WDAC policy, only the following EKUs are necessary
<EKUs>
<EKU ID="ID_EKU_WINDOWS" Value="010A2B0601040182370A0306" FriendlyName="" />
<EKU ID="ID_EKU_ELAM" Value="010A2B0601040182373D0401" FriendlyName="" />
<EKU ID="ID_EKU_HAL_EXT" Value="010a2b0601040182373d0501" FriendlyName="" />
<EKU ID="ID_EKU_WHQL" Value="010A2B0601040182370A0305" FriendlyName="" />
</EKUs>
In order to automatically remove unnecessary things from a policy file, such as the EKUs mentioned earlier, you can run a command like this:
Merge-CIPolicy .\Policy.xml -OutputFilePath .\Policy1.xml
It essentially merges a policy with itself, adding _0
to each ID and SignerID of the xml nodes which is easily removable using WDACConfig module, although it's not necessary to remove them at all, they are perfectly fine.
When you use -Audit
parameter of ConfigCI cmdlets such as Get-SystemDriver and New-CIPolicy, these 2 event logs are scanned
- AppLocker – MSI and Script event log
- CodeIntegrity - Operational
Sometimes there are files that are signed by 2 or more certificates, aka double signed files.
When FilePublisher level is used, WDAC creates rules for both of the intermediate certificates of those files, and each rule will have a signer assigned to it. If the file is either User mode only or Kernel mode only, then 2 Signers will be created for it, one for each certificate.
Depending on Kernel or use mode, 2 Allowed Signers are created for the file in either UMCI or KMCI Signing scenario sections.
However, if the file is a kernel mode driver and user mode driver, then 4 signers are created for it, 2 Allowed Signers in the UMCI Signing Scenario and 2 in the KMCI Signing scenario.
In the signer below
<Signer ID="ID_SIGNER_F_2" Name="Microsoft Windows Third Party Component CA 2014">
<CertRoot Type="TBS" Value="D8BE9E4D9074088EF818BC6F6FB64955E90378B2754155126FEEBBBD969CF0AE" />
<CertPublisher Value="Microsoft Windows Hardware Compatibility Publisher" />
<FileAttribRef RuleID="ID_FILEATTRIB_F_46" />
</Signer>
-
Name="Microsoft Windows Third Party Component CA 2014"
is the Common name of the Intermediate certificate of the file -
Value="D8BE9E4D9074088EF818BC6F6FB64955E90378B2754155126FEEBBBD969CF0AE"
is the TBS (To Be Signed) values of the same Intermediate certificate -
Value="Microsoft Windows Hardware Compatibility Publisher"
is the Common name of the Leaf certificate of the file
-
If 2 files have the same Leaf certificate CN and also have an Intermediate certificate in common (that has the same TBS and CN) then they should be listed under the same Signer.
-
Any Intermediate certificate in the certificate chain/path of a file can be used to allow a file using FilePublisher.
HVCI stands for Hypervisor-protected Code Integrity and it is a feature that uses virtualization-based security (VBS) to protect the Windows kernel from memory attacks. HVCI can be set to different options in a WDAC policy, such as Enabled, DebugMode, or Strict. Setting HVCI to Strict in a WDAC policy provides the highest level of protection for kernel mode code integrity, as it enforces these additional restrictions:
-
It prevents unsigned drivers from loading, even if they are allowed by the WDAC policy. It prevents drivers that are not compatible with HVCI from loading, even if they are signed and allowed by the WDAC policy.
-
It prevents drivers that have been tampered with or modified from loading, even if they are signed and allowed by the WDAC policy.
-
Setting HVCI to Strict in a WDAC policy can help prevent malware or attackers from exploiting vulnerabilities in kernel mode drivers or bypassing the WDAC policy enforcement.
-
A file can have only one root certificate at the end of the chain. The root certificate is always self-signed by the CA itself (meaning its IssuerCN and SubjectCN are the same) and it is the ultimate source of trust for the chain that validates it. Having more than one root certificate would imply that there are multiple chains of trust for the same file, which is not possible.
-
A file can have more than 1 intermediate certificate and there is no definitive limit for it, but in practice, it is recommended to keep the certificate chain as short as possible.
-
A file can have only one leaf certificate at the beginning of the chain. The leaf certificate is the one that belongs to the file itself and contains its public key and other information. Having more than one leaf certificate would imply that there are multiple files with different identities and keys, which is not possible.
-
Leaf, intermediate and root are the only types of certificates a file can have in a certificate chain. There are other types of certificates that are not part of a chain, such as self-signed certificates or wildcard certificates, but they are not relevant to WDAC policies.
WDAC policy for BYOVD Kernel mode only protection
- Create AppControl Policy
- Create Supplemental Policy
- System Information
- Configure Policy Rule Options
- Simulation
- Allow New Apps
- Build New Certificate
- Create Policy From Event Logs
- Create Policy From MDE Advanced Hunting
- Create Deny Policy
- Merge App Control Policies
- Deploy App Control Policy
- Get Code Integrity Hashes
- Get Secure Policy Settings
- Update
- Sidebar
- Introduction
- How To Generate Audit Logs via App Control Policies
- How To Create an App Control Supplemental Policy
- The Strength of Signed App Control Policies
- App Control Notes
- How to use Windows Server to Create App Control Code Signing Certificate
- Fast and Automatic Microsoft Recommended Driver Block Rules updates
- App Control policy for BYOVD Kernel mode only protection
- EKUs in App Control for Business Policies
- App Control Rule Levels Comparison and Guide
- Script Enforcement and PowerShell Constrained Language Mode in App Control Policies
- How to Use Microsoft Defender for Endpoint Advanced Hunting With App Control
- App Control Frequently Asked Questions (FAQs)
- Create Bootable USB flash drive with no 3rd party tools
- Event Viewer
- Group Policy
- How to compact your OS and free up extra space
- Hyper V
- Overrides for Microsoft Security Baseline
- Git GitHub Desktop and Mandatory ASLR
- Signed and Verified commits with GitHub desktop
- About TLS, DNS, Encryption and OPSEC concepts
- Things to do when clean installing Windows
- Comparison of security benchmarks
- BitLocker, TPM and Pluton | What Are They and How Do They Work
- How to Detect Changes in User and Local Machine Certificate Stores in Real Time Using PowerShell
- Cloning Personal and Enterprise Repositories Using GitHub Desktop
- Only a Small Portion of The Windows OS Security Apparatus
- Rethinking Trust: Advanced Security Measures for High‐Stakes Systems
- Clean Source principle, Azure and Privileged Access Workstations
- How to Securely Connect to Azure VMs and Use RDP
- Basic PowerShell tricks and notes
- Basic PowerShell tricks and notes Part 2
- Basic PowerShell tricks and notes Part 3
- Basic PowerShell tricks and notes Part 4
- Basic PowerShell tricks and notes Part 5
- How To Access All Stream Outputs From Thread Jobs In PowerShell In Real Time
- PowerShell Best Practices To Follow When Coding
- How To Asynchronously Access All Stream Outputs From Background Jobs In PowerShell
- Powershell Dynamic Parameters and How to Add Them to the Get‐Help Syntax
- RunSpaces In PowerShell
- How To Use Reflection And Prevent Using Internal & Private C# Methods in PowerShell