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.
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:
- Creating Windows Defender Firewall with Advanced Security rules
- 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:
There is also an easy built-in tool to create firewall rules called [.highlight]netsh[.highlight]:
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.
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:
- Understanding Network Access in Windows AppContainers by James Forshaw
- What The Filter (WTF) is Going on With Windows Filtering Platform by Sagie Dulce
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:
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]).
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:
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.
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:
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:
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.
After this is implemented, we can see the filters and providers that are created, with EDRSilencer successfully deleted:
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.
Sign Up for Blog Updates
Subscribe today and you’ll be the first to know when new content hits the blog.