├── applywdac-2016.png ├── applywdac-auto.png ├── applywdac-modern.png ├── LICENSE ├── README.md └── applywdac.ps1 /applywdac-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vu-ls/applywdac/HEAD/applywdac-2016.png -------------------------------------------------------------------------------- /applywdac-auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vu-ls/applywdac/HEAD/applywdac-auto.png -------------------------------------------------------------------------------- /applywdac-modern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vu-ls/applywdac/HEAD/applywdac-modern.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, wdormann 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ApplyWDACPolicy 2 | 3 | `applywdac.ps1` is a PowerShell script for applying WDAC policies, 4 | such as the [Microsoft recommended driver block 5 | rules](https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules). 6 | This script is designed for use on systems that do **NOT** currently 7 | have WDAC policies and associated management tools in place. If you 8 | are already using WDAC, you should merge WDAC policies using whichever 9 | tools and methods you already have in place. The target audience of 10 | this script are those who want to be able to apply WDAC rules easily, 11 | without requiring extensive knowledge of WDAC. 12 | 13 | ## Installation 14 | 15 | If you have the ability to run stand-along PowerShell scripts, simply 16 | run the `.\applywdac.ps1` script from a PowerShell prompt that is 17 | running with administrative privileges. Alternatively, you can paste 18 | the contents of 19 | [applywdac.ps1](https://raw.githubusercontent.com/wdormann/applywdac/main/applywdac.ps1) 20 | into a PowerShell prompt that is running with administrative 21 | privileges and subsequently run `ApplyWDACPolicy` with the appropriate 22 | arguments. Just be sure to use **`Ctrl+V` on your keyboard** to do the 23 | pasting, as pasting via right-click or even the edit menu at the top 24 | will interpret pasted content on a line-by-line basis as opposed to in 25 | block mode. 26 | 27 | ## Usage 28 | 29 | ``` 30 | # Import `blockeddrivers.xml` in whatever mode it specifies. e.g. the [Microsoft recommended driver block rules](https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules) are in audit mode by default. 31 | PS> .\applywdac.ps1 -xmlpolicy blockeddrivers.xml 32 | 33 | # Import `blockeddrivers.xml`, stripping out any "audit" options (therefore applying it in "enforcing" mode) 34 | PS> .\applywdac.ps1 -xmlpolicy blockeddrivers.xml -enforce 35 | 36 | # Same as above, but in "paste into PowerShell mode" 37 | PS> 38 | PS> ApplyWDACPolicy -xmlpolicy blockeddrivers.xml -enforce 39 | 40 | # "paste into PowerShell mode" automatically download and install compiled policy binary from Microsoft 41 | PS> 42 | PS> ApplyWDACPolicy -auto -enforce 43 | ``` 44 | 45 | Pre-Windows-1903 example usage: 46 | ![Windows Server 2016](applywdac-2016.png) 47 | 48 | Windows 1903 or later example usage: 49 | ![Windows Server 2016](applywdac-modern.png) 50 | 51 | Automatic download from Microsoft example usage, "paste into PowerShell" invocation: 52 | ![Windows Server 2016](applywdac-auto.png) 53 | 54 | ## HVCI Notes 55 | 56 | If you apply the [Microsoft recommended driver block 57 | rules](https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules), 58 | you may end up with 59 | [HVCI](https://learn.microsoft.com/en-us/windows/security/threat-protection/device-guard/enable-virtualization-based-protection-of-code-integrity) 60 | enabled on your system. While HVCI is an excellent mitigation against 61 | attacks and it should be used on every platform that can support it, 62 | there can be some edge cases where HVCI can interfere with the ability 63 | to use a system as intended. For example, a machine where VMware 64 | Workstation is installed and nested virtualization features are 65 | needed. In such cases, it may be necessary to disable HVCI to regain 66 | the ability to use the VMware Workstation native hypervisor. VMware 67 | has provided [instructions for how this can be 68 | accomplished](https://kb.vmware.com/s/article/2146361). 69 | 70 | Note that driver blocking with WDAC will still function as expected, 71 | even when HVCI is disabled. 72 | 73 | ## Undoing the changes made by this utility 74 | 75 | You may encounter a situation where applying the Microsoft recommended 76 | driver block rules policy interferes with something that you want to 77 | do. If this is the case and you're sure that you wish to have a 78 | vulnerable driver on your system, you can undo the changes made by 79 | this script. 80 | 81 | ### Removing automatic policy installation 82 | 83 | For systems that have applied the Microsoft recommended driver block 84 | rules using the `-auto` option, this tool downloads a blocklist binary 85 | from Microsoft and places it as 86 | `%windir%\system32\CodeIntegrity\SiPolicy.p7b`. To undo the driver 87 | policy changes, simply delete this file and reboot. 88 | 89 | ### Removing manual policy installation 90 | 91 | For systems where an XML policy has been installed, this tool places 92 | the compiled policy as 93 | `%windir%\system32\CodeIntegrity\CIPolicies\Active\{PolicyId}.cip`, 94 | where `PolicyId` is the GUID of the policy that you have applied. To 95 | undo the driver policy changes, simply delete this file and reboot. 96 | 97 | 98 | ## Contributing 99 | 100 | Pull requests are welcome. For major changes, please 101 | open an issue first to discuss what you would like to change. 102 | 103 | Please make sure to update tests as appropriate. 104 | 105 | ## License 106 | [BSD](https://choosealicense.com/licenses/bsd-2-clause/) 107 | -------------------------------------------------------------------------------- /applywdac.ps1: -------------------------------------------------------------------------------- 1 | <#PSScriptInfo 2 | 3 | .VERSION 1.0.2 4 | 5 | .AUTHOR Will Dormann 6 | 7 | .LICENSEURI https://opensource.org/licenses/BSD-2-Clause 8 | 9 | .SYNOPSIS 10 | Applies a WDAC XML policy file to a Windows system 11 | 12 | .DESCRIPTION 13 | This script will apply a WDAC XML policy file to a Windows system. 14 | Support is provided for both Multiple Policy Format files 15 | as well as legacy single-policy files. 16 | 17 | .PARAMETER xmlpolicy 18 | Specifies the WDAC XML Policy file 19 | 20 | .PARAMETER enforce 21 | Flag to specify that the policy is to be enforced, rather than audited. 22 | 23 | .EXAMPLE 24 | PS> .\applywdac.ps1 -xmlpolicy driverblocklist.xml -enforce 25 | Apply the WDAC policy contained in driverblocklist.xml in enforcing mode 26 | 27 | .EXAMPLE 28 | PS> .\applywdac.ps1 -xmlpolicy driverblocklist.xml 29 | Apply the WDAC policy contained in driverblocklist.xml in audit-only mode 30 | 31 | .EXAMPLE 32 | PS> .\applywdac.ps1 -auto -enforce 33 | Download and install the precompiled binary policy from Microsoft 34 | 35 | #> 36 | Param([string]$xmlpolicy, [switch]$enforce, [switch]$auto) 37 | 38 | try{ 39 | Add-Type -AssemblyName System.IO.Compression.FileSystem 40 | } catch { 41 | throw "This PowerShell instance is probably running in constrained mode. You will not be able to make WDAC changes." 42 | } 43 | 44 | function ApplyWDACPolicy { 45 | Param([string]$xmlpolicy, [switch]$enforce, [switch]$auto) 46 | 47 | if (($xmlpolicy -eq "") -and !($auto)) { 48 | Get-Help ApplyWDACPolicy -Detailed 49 | return 50 | } 51 | 52 | $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) 53 | if (-Not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { 54 | Write-Error "This script requires administrative privileges" 55 | return 56 | } 57 | 58 | If ([System.Environment]::OSVersion.Version.Major -lt 10) { 59 | Write-Error "Windows 10 or later is required to deploy WDAC policies." 60 | return 61 | } 62 | 63 | if ($auto) { 64 | If ([System.Environment]::OSVersion.Version.Build -eq 14393) { 65 | Write-Error "This version of Windows is too old to successfully connect to Microsoft using HTTPS to download rules." 66 | Write-Warning "Driver policies must be installed on this platform using the -xml option on a local file." 67 | Write-Warning "See https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules for the current Microsoft block list" 68 | return 69 | } 70 | if ($enforce) { 71 | $policybin = "SiPolicy_Enforced.p7b" 72 | } 73 | else { 74 | Write-warning "This policy is being deployed in audit mode. Rules will not be enforced!" 75 | Write-warning "Try again with the -enforce option to make this policy enforced." 76 | $policybin = "SiPolicy_Audit.p7b" 77 | } 78 | 79 | $binpolicyzip = [IO.Path]::GetTempFileName() | Rename-Item -NewName { $_ -replace 'tmp$', 'zip' } -PassThru 80 | Write-Output "Downloading https://aka.ms/VulnerableDriverBlockList" 81 | Invoke-WebRequest https://aka.ms/VulnerableDriverBlockList -UseBasicParsing -OutFile $binpolicyzip 82 | $zipFile = [IO.Compression.ZipFile]::OpenRead($binpolicyzip) 83 | Write-Output "Extracting $policybin to $env:windir\system32\CodeIntegrity\SiPolicy.p7b" 84 | $zipFile.Entries | Where-Object Name -like $policybin | ForEach-Object { [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, "$env:windir\system32\CodeIntegrity\SiPolicy.p7b", $true) } 85 | Get-ChildItem "$env:windir\system32\CodeIntegrity\SiPolicy.p7b" 86 | Write-Output "`nPlease Reboot to apply changes" 87 | } 88 | else { 89 | 90 | $xmlpolicy = (Resolve-Path "$XmlPolicy") 91 | $xmloutput = New-TemporaryFile 92 | 93 | Copy-Item -path $xmlpolicy -Destination $xmloutput -PassThru | Set-ItemProperty -name isreadonly -Value $false 94 | 95 | [xml]$Xml = Get-Content "$xmloutput" 96 | # Retrieve the namespace (needed for WDAC policies) 97 | $namespaceURI = $Xml.DocumentElement.NamespaceURI 98 | 99 | # Set up an XML namespace manager 100 | $namespace = New-Object System.Xml.XmlNamespaceManager($Xml.NameTable) 101 | $namespace.AddNamespace("ns", $namespaceURI) 102 | 103 | # Perform a namespace-aware XPath query 104 | $auditModeEnabled = $Xml.SelectNodes("//ns:Rules/ns:Rule/ns:Option[text()='Enabled:Audit Mode']", $namespace) 105 | 106 | if ($auditModeEnabled.Count -gt 0) { 107 | $auditmode = 1 108 | } else { 109 | $auditmode = 0 110 | } 111 | 112 | If ( $xml.SiPolicy.PolicyTypeID ) { 113 | Write-Output "Legacy XML format detected" 114 | If ([System.Environment]::OSVersion.Version.Build -eq 14393) { 115 | # Windows 1607 doesn't understand the MaximumFileVersion attribute. Remove it. 116 | Write-Output "Removing MaximumFileVersion attributes, as this version of Windows cannot handle them..." 117 | $xml.SiPolicy.Filerules.ChildNodes | ForEach-Object -MemberName RemoveAttribute("MaximumFileVersion") 118 | Write-Output "Removing Update Policy No Reboot option, as this version of Windows cannot handle them..." 119 | $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) 120 | $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI) 121 | $node = $xml.SelectSingleNode("//ns:Rules/ns:Rule[ns:Option='Enabled:Update Policy No Reboot']", $ns) 122 | if ( $node ) { 123 | $node.ParentNode.RemoveChild($node) 124 | } 125 | $xml.Save((Resolve-Path "$xmloutput")) 126 | } 127 | If ([System.Environment]::OSVersion.Version.Build -le 18362.900) { 128 | # Install on system that doesn't support multi-policy 129 | if ($enforce -or ($auditmode -eq 0)) { 130 | Set-RuleOption -FilePath "$xmloutput" -Option 3 -Delete 131 | } 132 | else { 133 | Write-warning "This policy is being deployed in audit mode. Rules will not be enforced!" 134 | Write-warning "Try again with the -enforce option to make this policy enforced." 135 | } 136 | $policytypeid = $xml.SiPolicy.PolicyTypeID 137 | if ($policytypeid -notmatch "{A244370E-44C9-4C06-B551-F6016E563076}") { 138 | Write-Warning "This WDAC policy uses a PolicyTypeID other than {A244370E-44C9-4C06-B551-F6016E563076}. Applying this policy may not have the expected outcome." 139 | } 140 | ConvertFrom-CIPolicy -xmlFilePath "$xmloutput" -BinaryFilePath ".\SiPolicy.p7b" 141 | $PolicyBinary = ".\SIPolicy.p7b" 142 | $DestinationBinary = $env:windir + "\System32\CodeIntegrity\SiPolicy.p7b" 143 | Copy-Item -Path $PolicyBinary -Destination $DestinationBinary -Force 144 | Invoke-CimMethod -Namespace root\Microsoft\Windows\CI -ClassName PS_UpdateAndCompareCIPolicy -MethodName Update -Arguments @{FilePath = $DestinationBinary } 145 | } 146 | else { 147 | # Install on system that does support multi-policy 148 | $policytypeid = $xml.SiPolicy.PolicyTypeID 149 | if ($enforce -or ($auditmode -eq 0)) { 150 | Set-RuleOption -FilePath "$xmloutput" -Option 3 -Delete 151 | } 152 | else { 153 | Write-warning "This policy is being deployed in audit mode. Rules will not be enforced!" 154 | Write-warning "Try again with the -enforce option to make this policy enforced." 155 | } 156 | ConvertFrom-CIPolicy -xmlFilePath "$xmloutput" -BinaryFilePath ".\$policytypeid.cip" 157 | $PolicyBinary = ".\$policytypeid.cip" 158 | $DestinationFolder = $env:windir + "\System32\CodeIntegrity\CIPolicies\Active\" 159 | Copy-Item -Path $PolicyBinary -Destination $DestinationFolder -Force 160 | } 161 | } 162 | ElseIf ( $xml.SiPolicy.PolicyID ) { 163 | Write-Output "Multiple Policy Format XML detected" 164 | If ([System.Environment]::OSVersion.Version.Build -le 18362.900) { 165 | Write-Error "This version of Windows does not support Multiple Policy Format XML files" 166 | return 167 | } 168 | else { 169 | # Install on system that does support multi-policy 170 | $policytypeid = $xml.SiPolicy.PolicyID 171 | if ($enforce -or ($auditmode -eq 0)) { 172 | Set-RuleOption -FilePath "$xmloutput" -Option 3 -Delete 173 | } 174 | else { 175 | Write-warning "This policy is being deployed in audit mode. Rules will not be enforced!" 176 | Write-warning "Try again with the -enforce option to make this policy enforced." 177 | } 178 | ConvertFrom-CIPolicy -xmlFilePath "$xmloutput" -BinaryFilePath ".\$policytypeid.cip" 179 | $PolicyBinary = ".\$policytypeid.cip" 180 | $DestinationFolder = $env:windir + "\System32\CodeIntegrity\CIPolicies\Active\" 181 | Copy-Item -Path $PolicyBinary -Destination $DestinationFolder -Force 182 | } 183 | } 184 | Else { 185 | Write-Error "Cannot determine XML format." 186 | return 187 | } 188 | 189 | #Save a copy of the potentially-modified XML file for our record 190 | $appliedpolicy = [io.path]::GetFileNameWithoutExtension($xmlpolicy) + "-applied.xml" 191 | Write-Output "Copy of applied policy XML saved as: $appliedpolicy`n" 192 | Copy-Item -path $xmloutput -Destination $appliedpolicy -PassThru | Set-ItemProperty -name isreadonly -Value $false 193 | Write-Output "`nPlease Reboot to apply changes" 194 | } 195 | } 196 | 197 | if ($auto) { 198 | # Use binary policy from Microsoft 199 | if ($enforce) { 200 | ApplyWDACPolicy -auto -enforce 201 | } 202 | else { 203 | ApplyWDACPolicy -auto 204 | } 205 | } 206 | else { 207 | # Compile our own specified policy 208 | if ($enforce) { 209 | ApplyWDACPolicy -xmlpolicy $xmlpolicy -enforce 210 | } 211 | else { 212 | ApplyWDACPolicy -xmlpolicy $xmlpolicy 213 | } 214 | } 215 | --------------------------------------------------------------------------------