A .NET library and PowerShell module for managing Windows RPC filters
The DSInternals.Win32.RpcFilters library allows .NET applications to directly interact with Windows RPC Fiters, part of the Windows Filtering Platform (WFP).
The DSInternals.RpcFilters PowerShell module
exposes the functionality of the DSInternals.Win32.RpcFilters library through PowerShell cmdlets.
The following example shows how the DCSync attack could be blocked on a Domain Controller using RPC filters:
Import-Module -Name DSInternals.RpcFilters
# Create 3 RPC filters targeting the Directory Replication Service (DRS) Remote Protocol
New-RpcFilter -Name 'DCSync-Allow-DC01' -WellKnownOperation IDL_DRSGetNCChanges -IPAddress 10.0.0.1 -Action Permit -Persistent
New-RpcFilter -Name 'DCSync-Allow-DC02' -WellKnownOperation IDL_DRSGetNCChanges -IPAddress 10.0.0.2 -Action Permit -Persistent
New-RpcFilter -Name 'DCSync-Block-Default' -WellKnownOperation IDL_DRSGetNCChanges -Action Block -Persistent
# Check the current configuration
Get-RpcFilter
<# Sample output:
Name: DCSync-Allow-DC02
Description: RPC Filter
FilterId: 99321, FilterKey: 745889a1-207c-4ea0-8207-e97a8ad45b41, ProviderKey: N/A
Action: Permit
Audit: False, Persistent: True, BootTimeEnforced: False, Disabled: False
EffectiveWeight: 0x7e0000000001007, Weight: N/A
Conditions:
Protocol = MS-DRSR
Operation = IDL_DRSGetNCChanges (3)
RemoteAddress = 10.0.0.2/32
Name: DCSync-Allow-DC01
Description: RPC Filter
FilterId: 99320, FilterKey: bc95f1b0-a1f6-4f01-a2d0-8e3d61619b3b, ProviderKey: N/A
Action: Permit
Audit: False, Persistent: True, BootTimeEnforced: False, Disabled: False
EffectiveWeight: 0x7e0000000001007, Weight: N/A
Conditions:
Protocol = MS-DRSR
Operation = IDL_DRSGetNCChanges (3)
RemoteAddress = 10.0.0.1/32
Name: DCSync-Block-Default
Description: RPC Filter
FilterId: 99322, FilterKey: 5c9a49fd-706c-423d-bddf-75afbb2eb051, ProviderKey: N/A
Action: Block
Audit: False, Persistent: True, BootTimeEnforced: False, Disabled: False
EffectiveWeight: 0x7e0000000000007, Weight: N/A
Conditions:
Protocol = MS-DRSR
Operation = IDL_DRSGetNCChanges (3)
#>
# Remove the previously created filters
Get-RpcFilter | Where-Object Name -like 'DCSync-*' | Remove-RpcFilterTip
More examples can be found in the PowerShell module documentation.
The Windows built-in netsh tool can also be used to manage RPC filters,
but it has many limitations:
- Filter names and descriptions cannot be set.
- Raw protocol UUIDs and OpNums must be used instead of well-known protocol and operation names.
- IP address conditions are not supported.
- Auditing cannot be enabled for blocked operations.
The following example shows how RPC filters can be managed by the .NET interop library.
Important
This code is only meant to showcase all the possible parameters, so the resulting filter is not meaningful at all.
using DSInternals.Win32.RpcFilters;
using System.Net;
// Open a Windows Filtering Platform (WFP) session
using var fw = new RpcFilterManager();
// Fetch the effective list of RPC filters
var filters = fw.GetFilters();
// Register a new RPC filter
var filter = new RpcFilter()
{
Name = "TestFilter",
Description = "Test filter description",
Action = RpcFilterAction.Permit,
InterfaceUUID = WellKnownProtocols.RemoteRegistry.ToInterfaceUUID(),
OperationNumber = 25,
Transport = RpcProtocolSequence.ncacn_ip_tcp,
NamedPipe = "\\PIPE\\winreg",
LocalPort = 56345,
DcomAppId = Guid.Parse("10000000-0000-0000-0000-000000000002"),
SDDL = "D:(A;;CC;;;BA)",
SecurityDescriptorNegativeMatch = true,
Audit = RpcFilterAuditOptions.Enabled,
IsPersistent = true,
AuthenticationLevel = RpcAuthenticationLevel.PacketPrivacy,
AuthenticationLevelMatchType = NumericMatchType.LessThan,
AuthenticationType = RpcAuthenticationType.Kerberos,
IsBootTimeEnforced = false,
ImageName = "svchost.exe",
RemoteAddress = IPAddress.Parse("fe80::bf1c:8c8e:f09d:c074"),
LocalAddress = IPAddress.Parse("10.255.255.0"),
LocalAddressMask = 24,
Weight = 3
};
ulong id = fw.AddFilter(filter);
// Delete the freshly registered RPC filter
fw.RemoveFilter(id);Tip
More information can be found in the .NET API documentation.
To monitor blocked or permitted RPC operations, auditing for RPC events must be enabled first. This can be done in multiple ways:
- The
auditpol.exe /set /subcategory:"RPC Events" /success:enable /failure:enablecommand must be executed in an elevated command prompt . - The custom Enable-RpcFilterAuditing cmdlet can be used in PowerShell.
- Administrators would prefer to use Active Directory Group Policy (Computer Configuration ⇒ Policies ⇒ Windows Settings ⇒ Security Settings ⇒ Advanced Audit Policy Configuration ⇒ System Audit Policies ⇒ Object Access ⇒ Audit RPC Events)
Once auditing is enabled, the corresponding RPC events will be created in the Security event log:
The Get-RpcFilterEvent cmdlet can be used to fetch these RPC audit events, and to translate most identifiers into human-readable names:
Warning
Several filter conditions are not evaluated by the filtering engine as expected or documented by Microsoft, leading to inconsistent behavior.
The ability to filter RPC operations by their operation number is only available on Windows 11 24H2 and Windows Server 2025 or later by default. However, the October 2025 Cumulative Update backports this feature to Windows 10, Windows Server 2022, and Windows Server 2019 as well. Without this update, the underlying FWPM_CONDITION_RPC_OPNUM filter condition is ignored by the filtering engine on these OS versions.
Windows Server 2016 and older systems do not even support operation number filtering at the API level
and reject attempts to create such filters by returning the FWP_E_CONDITION_NOT_FOUND error.
The same behavior can be observed in RTM versions of Windows Server 2019 and Windows Server 2022 before Windows Update is launched.
Filter conditions based on subnets, i.e. specifying IPv4 address masks or IPv6 prefix lengths, will not match any RPC traffic. The FWP_MATCH_RANGE operator does not work with IP addresses either.
Named pipe names are case sensitive. For example, a filter with the named pipe condition \PIPE\WINREG will not match
Remote Registry connections using the \PIPE\winreg named pipe.
Although the WFP API supports case-insensitive string comparisons through the FWP_MATCH_EQUAL_CASE_INSENSITIVE operator,
named pipe names are unfortunately stored as blobs instead of strings and thus only support the FWP_MATCH_EQUAL operator.
Filters containing IP address conditions will never match RPC over named pipe traffic on system versions lower than Windows 11 25H2.
The filtering engine sometimes identifies authentication type as RPC_C_AUTHN_NONE instead of RPC_C_AUTHN_WINNT
and authentication level as RPC_C_AUTHN_LEVEL_DEFAULT instead of RPC_C_AUTHN_LEVEL_PKT_PRIVACY for ncacn_np traffic.
This seems to be the case of the MS-SCMR protocol, while MS-TSCH and MS-EVEN behave as expected. Further investigation is required.
Kerberos vs. Negotiate authentication type matching seems to be unreliable.
RPC filters typically do not apply to local RPC calls,
even when a filter condition explicitly targets the ncalrpc protocol sequence (transport layer).
The exact behavior is application-specific and might not always be intuitive:
# This will bypass RPC filters:
Get-WinEvent -ListLog System
# But this will actually be caught by RPC filters:
Get-WinEvent -ComputerName localhost -ListLog SystemSince Windows 11 25H2 and Windows Server 2025, the API supports optional auditing of RPC call parameters through the new FWPM_CONTEXT_RPC_AUDIT_BUFFER_ENABLED flag.
This feature is exposed through the .NET interop library and PowerShell module:
New-RpcFilter -Name 'SCMR-Audit' -WellKnownProtocol ServiceControlManager -Action Permit -Audit EnabledWithParamsHowever, enabling this flag does not seem to have any effect yet.
The filtering engine is unable to identity a couple of well-known RPC protocols
and only sees a blank interface UUID (00000000-0000-0000-0000-000000000000).
We have observed this behavior for the MS-WCCE
and MS-VDSP protocols so far.
The .NET wrapper currently only supports relative weights in the 0-15 range when creating new filters. Support for absolute weights in the 0-18446744073709551615 range is not yet implemented.
Only the equality operator (FWP_MATCH_EQUAL) is currently supported for filter conditions by the tool.
Although the WFP API supports a wide range of match types, most of them are not even relevant for RPC filters.
Tip
See another project of mine, Active Directory Firewall, for comprehensive guidelines on configuring Windows Firewall on Domain Controllers, including RPC filters.
- Ned Pyle (Microsoft): RPC over IT/Pro
- Sagie Dulce (Zero Networks): Stopping Lateral Movement via the RPC Firewall
- Ophir Harpaz & Stiv Kupchik (Akamai): A Definitive Guide to the Remote Procedure Call (RPC) Filter
- James Spencer (CrowdStrike): Windows RPC Interface Database
- James Forshaw (Google Project Zero): Calling Local Windows RPC Servers from .NET


