-
Notifications
You must be signed in to change notification settings - Fork 160
Script Enforcement and PowerShell Constrained Language Mode in WDAC App Control Policies
This article explores some of the technical details of how to deploy an App Control policy that uses Script Enforcement and forces PowerShell to run in Constrained Language Mode. It expands aspects of this topic that are not covered enough in the official docs.
Tip
Check out these 2 documents from Microsoft for more info and basics:
Below are the required steps to enable Script Enforcement and allow a PowerShell module to run in Constrained Language Mode, if its code meets the requirements of it.
The PowerShell module that you intend to use in Constrained Language Mode must be completely signed, that means all of its .psm1
and .psd1
files must be signed by a code signing certificate.
The Code Signing certificate you're going to use to sign the PowerShell module files with can be a self-signed certificate or a certificate from a trusted certification authority (CA).
If the certificate you used to sign the PowerShell module files with is from a trusted certification authority (CA) and the root certificate of that CA exists in the "Trusted Root Certification Authorities" store of either the Local Machine or Current User certificate store, then you're good to go, but if the certificate is self-signed, you need to add the certificate's root certificate to either of those locations.
For instance, if you generated a Code Signing certificate from Windows Server Active Directory Certificate Services, and you used that certificate to sign the PowerShell module files, you need to export the root certificate containing the public key, to a .cer
file and then add it to one of the locations mentioned earlier. Adding the leaf certificate, which is the one you used to sign the module files with, to those locations, will not count and won't allow the signed PowerShell module to run in Constrained Language Mode.
The App Control base policy you're going to deploy must have 0 Enabled:UMCI
and it must not have the 11 Disabled:Script Enforcement
rule options.
The root certificate's details must be added as a Signer rule in an App Control policy in the User-Mode Signing Scenario.
Adding the Certificate's Signer rule to the Kernel-mode Signing Scenario does not allow the modules signed by that certificate to run, which is expected.
For better management, you should allow the certificate in a new supplemental policy.
Here is an example of a valid Supplemental policy that allows a root certificate as a signer.
<?xml version="1.0" encoding="utf-8"?>
<SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy" PolicyType="Supplemental Policy">
<VersionEx>1.0.0.0</VersionEx>
<PlatformID>{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}</PlatformID>
<Rules>
<Rule>
<Option>Enabled:Unsigned System Integrity Policy</Option>
</Rule>
</Rules>
<EKUs />
<FileRules />
<Signers>
<Signer ID="ID_SIGNER_S_1_1" Name="Root Certificate">
<CertRoot Type="TBS" Value="e3fbf9a3dc3022eab22b5e961bc6fee45782ae8aaed1d8402f2101a5f393db876444ef1d0e302f03b64463bae816f701cc5cda41068a8bf1954a0cd262eb9d6f" />
</Signer>
</Signers>
<SigningScenarios>
<SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS_1" FriendlyName="Auto generated policy on 04-26-2024">
<ProductSigners />
</SigningScenario>
<SigningScenario Value="12" ID="ID_SIGNINGSCENARIO_WINDOWS" FriendlyName="Auto generated policy on 04-26-2024">
<ProductSigners>
<AllowedSigners>
<AllowedSigner SignerId="ID_SIGNER_S_1_1" />
</AllowedSigners>
</ProductSigners>
</SigningScenario>
</SigningScenarios>
<UpdatePolicySigners />
<CiSigners>
<CiSigner SignerId="ID_SIGNER_S_1_1" />
</CiSigners>
<HvciOptions>2</HvciOptions>
<BasePolicyID>{7558D4BF-69E3-45CA-9C52-915E48A7C50E}</BasePolicyID>
<PolicyID>{32C551AF-C243-477A-9955-D37EDF435414}</PolicyID>
<Settings>
<Setting Provider="PolicyInfo" Key="Information" ValueName="Name">
<Value>
<String>Supplemental Policy</String>
</Value>
</Setting>
</Settings>
</SiPolicy>
As you can see, we need the TBS Hash value of the root certificate.
You can use the AppControl Manager to create a supplemental policy that allows the certificates you select to be allowed by App Control.
Refer to this page for more information
Tip
A manual way to get the TBS Hash value of a certificate is using the following command, which also works for signed files and will show the details of the certificates in the chain as well.
certutil.exe –v <Path To .cer file>
When an App Control policy with script enforcement is deployed and you try to import an unauthorized module, you might see different errors. For instance, you might see an error about classes not being allowed or other reasons for a module not being able to load, but in essence, the PowerShell engine is trying to load the module in Constrained Language Mode and the module is failing to meet the requirements, most likely because:
- The module you're trying to load is not signed
- The module you're trying to load is signed but the certificate's root is not trusted by the system
- The module you're trying to load is signed but at least one of its files is tampered with and has a hash mismatch. Even adding a single space on an empty line causes hash mismatch, which is expected.
- 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
- Merge App Control Policies
- Deploy App Control Policy
- Get Code Integrity Hashes
- Get Secure Policy Settings
- Update
- Introduction
- App Control for Lightly Managed Devices
- App Control for Fully managed device - Variant 1
- App Control for Fully managed device - Variant 2
- App Control for Fully managed device - Variant 3
- App Control for Fully managed device - Variant 4
- App Control Notes
- How to Create and Deploy a Signed App Control Policy
- 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)
- New-WDACConfig
- New-SupplementalWDACConfig
- Remove-WDACConfig
- Edit-WDACConfig
- Edit-SignedWDACConfig
- Deploy-SignedWDACConfig
- Confirm-WDACConfig
- New-DenyWDACConfig
- Set-CommonWDACConfig
- New-KernelModeWDACConfig
- Get-CommonWDACConfig
- Remove-CommonWDACConfig
- Assert-WDACConfigIntegrity
- Test-CiPolicy
- Get-CiFileHashes
- Get-CIPolicySetting
- 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