This is some text inside of a div block.
Glitch effect

Silencing the EDR Silencers

Contributors:
Special thanks to our Contributors:
Glitch effectGlitch effectGlitch effect
Glitch banner

As many security practitioners know, tampering with Endpoint Detection and Response (EDR) products is a deep desire for threat actors and red teamers alike. I spoke about this briefly at BlackHat this year in my “EDR Blinded, Now What?” Huntress booth talk.

Speaking at BlackHat. Photo cred to my twin John Hammond.

In one of the slides, I talked about how one of the most common ways to “blind” EDRs is to apply firewall rules against the desired EDR applications. This technique is unique in the way that an attacker doesn’t need to directly access an EDR’s application themselves (open a handle to the process or file). Instead, they alter the application’s ability to communicate outbound to their server, as well as alter the server’s ability to communicate inbound to the application. So, although the EDR can collect telemetry of an action, those actions aren't being sent up for detections or investigations. In this blog, I'll touch on this technique and discuss how products can protect themselves from this attack. 

Blocking Mechanisms 

While we discuss the various ways one might block application's network communications, two ways really come to mind that are the most prevalent today: 

  1. Creating Windows Defender Firewall with Advanced Security rules
  2. Creating Windows Filtering Platform (WFP) rules 

Now, that might sound repetitive because it slightly is. That’s because the built-in Windows Defender Firewall leverages the Windows Filtering Platform to enforce its rules. However, I call it out because, as we’ll see later, we have to adjust the solution because depending on how you interact with each feature, the settings are set in different locations. 

Note: Before we proceed, it’s important to state that we’ll only be looking at default Windows firewall capabilities, not third-party ones. This blog also only focuses on when firewall rules are set via the Windows Firewall or WFP.

Windows FirewallI

The Windows Firewall has the ability to create custom rules that either allow or disallow an application to speak out through the network. Both inbound and outbound. There are no restrictions on which processes are targeted by these firewall rules, so as long as an attacker has local administrator rights they can successfully add an EDR agent into the firewall rule and block network connections. Most people have probably seen the following page as it relates to the Windows Firewall:

Figure 1: Windows Defender Firewall with Advanced Security Window

There is also an easy built-in tool to create firewall rules called [.highlight]netsh[.highlight]:

Figure 2: netsh advfirewall example

For something more custom, someone could leverage the INetFwRule and INetFwRules COM interfaces. Users can implement this themselves quite easily. A well-known tool that does this is EDRSandblast, which eventually leverages the Add method in the [.highlight]INetFwRules[.highlight] COM interface to create a new firewall rule against a known EDR binary.

Figure 3: EDRSandblast firewall creation example

Now, it’s good to note that with Windows AV turned on, Defender does block firewall rules being made against [.highlight]MsMpEng.exe[.highlight]. However, the key point is that this can be done against any EDR, and if they’re not monitoring, the network communications will be cut off. When these firewall rules are created, they’re actually stored in the registry under:

[.highlight]HKLM\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules\{GUID}[.highlight]

[.highlight]{GUID}[.highlight] represents the firewall rule. This is stored as a [.highlight]REG_SZ[.highlight] value where the data holds the information about the rule:

v2.32|Action=Block|Active=TRUE|Dir=In|App={application-path}|Name={firewall-rule-name}|Desc={firewall-rule-name}|

Let’s touch on the most important bits of this rule: 

  • Action - the firewall action to take (allow or block)
  • Active - whether or not the firewall rule is currently active or not
  • Dir - direction to permit or deny communication between either In(bound) or Out(bound)
  • App - the application to block or allow
  • Name - firewall rule name
  • Desc (optional) - description of the firewall

There are other optional flags that can be put into the string as well. The three biggest tags here are Action, Dir, and App.

So before we move forward into the WFP, let’s remember the registry key [.highlight]HKLM\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules\{GUID}[.highlight]. This will come in handy later when we discuss solutions.

Windows Filtering Platform (WFP)

The Windows Firewall leverages the Windows Filtering Platform to enforce its rules. Here, we won’t go in-depth about the internals of the WFP simply because we believe that a lot of other great researchers have. In fact, the following are great resources: 

Interacting with the WFP is a lot easier because there are direct APIs that we can take advantage of. A list of WFP APIs can be found here. For purposes of creating a WFP filter, the desired API is FwpmFilterAdd0. Many reading this blog have likely heard of EDRSilencer. This function is leveraged to create a WFP filter for both IPv4 and IPv6 addresses. When these rules are applied, there are two things that have to exist:

  • A provider - policy provider that is used for the management of the filter
  • A filter (inbound and outbound) - rule that if the conditions are met, takes the actions specified 

There are four types of run-time filters that users can interact with. Dynamic, Static, Persistent, and Built-in. The most valuable are persistent filters to an attacker, as they live until the filter is removed. When filters are set, they’re stored in the registry just like firewall rules, just in a different location:

Figure 4: Procmon output of WFP filters and provider being set

Each provider and filter is stored as a [.highlight]{GUID}[.highlight] value, and the filter data is stored as a byte array ([.highlight]REG_BINARY[.highlight]).

Figure 5: WFP filter byte array example

This can make parsing this data a little more difficult than the firewall rules above just because it isn’t just a simple string value. However, an easy way to interact with filters is with the [.highlight]Get-FwFilter[.highlight] PowerShell cmdlet. For example, you can get the information about a filter via the [.highlight]Get-FwFilter[.highlight] cmdlet if you have the [.highlight]FilterId[.highlight] or [.highlight]FilterKey[.highlight]:

FilterID
FilterKey

This is a great option if you’re curious what a specific filter is doing on your machine. Now, let’s see how to stop this from happening against an EDR application!

Solution 

We’ve identified that firewall rules and WFP filters are both eventually set in the registry. This is great for anyone trying to pick up on this activity because there are multiple ways to monitor the registry. We’d like to propose two avenues that a product could take if they want to stop this tampering technique in its tracks: Prevention and Immediate Removal.

Prevention

Products can either prevent it by leveraging a pre-callback routine for [.highlight]RegSetValue[.highlight] (RegNtPreSetValueKey). If a product has access to the kernel via a driver, then they could leverage RegNtPreSetValueKey to receive notifications when any registry value set operation is performed in the registry. Upon doing so, they could parse out the registry path and the data being set, and if it matched, they could return [.highlight]STATUS_ACCESS_DENIED[.highlight] to prevent that key from being set. A successful implementation would look something like the following: 

Figure 6: EDRSandblast failing to create firewall rules

You can see that the firewall rules aren't successfully created because they're blocked through the registry pre-callback [.highlight]RegNtPreSetValueKey[.highlight] notification. This works great from a prevention standpoint, but to be honest, I don’t always think it’s a good idea to parse or process data in the kernel unless it’s really lightweight. And although this works well for the firewall rules, that data is stored as a string value, where the WFP filters are stored as a byte array. Like the firewall rules above, this shouldn’t be processed/parsed in the kernel.

Immediate Removal

The methodology of “immediate removal” is similar to the method above, except that you’re technically allowing the undesired action to take place before doing anything about it. This can be done by monitoring for these registry value set operations via a post-callback (RegNtPostSetValueKey). This callback is notified once the action has already taken place in the registry. Now, someone could still process/parse this data in the kernel and deal with it, but I recommend storing the post-callback data and shipping it down to a user-mode agent so that it can take care of the parsing and processing. Figure 7 shows a very high-level architecture of how this can be done. There are many ways to do this, and this isn’t the only right way, but this is just how I did it when I created the proof-of-concept within JonMon.

Figure 7: Basic EDR architecture for registry post-callback

Once the data is successfully shipped down to the user-mode agent and parsed, then the agent can safely get rid of the rules. You can’t just delete the registry keys because the rules/filters aren't immediately reset. Instead, you must remove them in a way so that the filtering engine refreshes after the removal. You could delete the registry key, but then you’d have to reboot the machine. Obviously, this approach isn’t an appropriate option, as products want to do modifications during runtime. There are some effective options to achieve this, however. For firewall rules, I leveraged COM to do this:

Figure 8: Code example for INetFwRules::Remove

I validated that the registry value held the undesired firewall policy and used the INetFwRules Remove Method to remove the firewall policy. Figure 9 shows how it looks after implementation:

Figure 9: Example of malicious firewall rules being removed in real-time

You can see the rules were successfully created but immediately removed, rendering the tampering technique useless. 

For the filters and providers within the WFP, I leveraged the FwpmFilterDeleteById0 function to delete the filter and the FwpmProviderDeleteByKey0 function to delete the provider.

Figure 10: Code example of removing malicious WFP filters and providers

After this is implemented, we can see the filters and providers that are created, with EDRSilencer successfully deleted:

Figure 11: Example of malicious WFP filters being removed in real-time

While this method might not be "preventing" the rules from being written, it's just as effective. The product doesn’t need to parse and process this data in the kernel, and the removal is almost immediate. Lastly, you don’t have to use the registry callbacks, as the WFP has the 5447 security event that states when a new rule is created. Someone could monitor for that and perform the same actions as above to remove that rule.

Conclusion

Tampering with EDRs is a very hot topic, and I see many people talking about leveraging firewall policies and WFP filters to blind EDRs. It’s clear this is very effective. It’s also unique, as the attacker doesn’t have to interface with the EDR’s processes directly. I’ve yet to see anyone go in-depth on how to stop or mitigate this tamper technique, so I wanted to provide some potential solutions. I hope this helps you understand this tampering technique better and how to mitigate it.

Want to dive into even more attacker techniques? Join us at Tradecraft Tuesday! No products, no pitches—just tradecraft.

Categories
Share

Sign Up for Blog Updates

Subscribe today and you’ll be the first to know when new content hits the blog.

By submitting this form, you accept our Privacy Policy
Oops! Something went wrong while submitting the form.
Huntress at work
Threat Analysis
Threat Analysis