Windows Firewall : Port Scanning Prevention Filter
Port Scanning Prevention Filter
WFP Stealth mode filter
Recently I’ve had the opportunity to handle several cases where, at first glance, it would appear as though the firewall was rejecting inbound connections from another node on the network. The situation would seem simple enough:
NodeA tries to connect to NodeB through a newly created inbound port, but the connection fails.
To identify the problem, we need to get a simultaneous network capture from NodeA and NodeB to analyze the behavior of the TCP connection. In the below example, I will use NodeA as the source and NodeB as the destination for an SQL connection failure. This is just an example, and all steps for troubleshooting can be used in other network connection failure scenarios as well.
From NodeA (10.0.0.10):
First let’s analyze the trace on the source side (NodeA):
9892 w3wp.exe (4308) 10.0.0.10 10.0.0.11 TCP TCP: Flags=......S., SrcPort=60678, DstPort=1433
10115 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9592] Flags=......S., SrcPort=60678, DstPort=1433
10409 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9592] Flags=......S., SrcPort=60678, DstPort=1433
Here we see the initial SYN packet sent to begin the three-way handshake between NodeA and NodeB (for more explanation on the three-way handshake, reference this technical content: http://support.microsoft.com/kb/172983/EN-US). When no SYN/ACK is received from NodeB, NodeA retransmits the SYN three seconds later. Again, no SYN/ACK is received so NodeA retransmits for a final time before giving up. Normally, this could indicate that the SYN packet is not making it to NodeB, which is why we took a simultaneous capture to compare and confirm that the packet actually made it.
From NodeB (10.0.0.11):
Now let’s analyze the trace on the destinaion side (NodeB):
9854 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:Flags=......S., SrcPort=60678, DstPort=1433
10047 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9554]Flags=......S., SrcPort=60678, DstPort=1433
10359 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9554]Flags=......S., SrcPort=60678, DstPort=1433
So from NodeB, we see the exact same behavior. This confirms that there is no packet loss on the physical network as we can see the exact same packets in both captures. So, what’s going on here? Why would NodeB see these packets and act as though nothing is going on? This is where Netsh Scenario tracing comes into play. There are several different scenario captures available using Netsh (but we’ll leave that for another day); our focus will be on the scenarios that capture WFP behavior.
ETW Data Capture:
In this particular capture, we will be interested in using the following two commands during a reproduction of the issue:
Netsh wfp capture start
Netsh trace start scenario=NetConnection capture=yes report=yes
<Reproduce the issue>
Netsh wfp capture stop
Netsh trace stop
The data these commands provide gives us a deeper look into the network stack that will shed some light on why NodeB doesn’t respond. Since it was NodeB that didn’t respond we will focus our analysis there. Network Monitor 3.4 can be used to open the report.etl that we get from the Netconnection scenario tracing.
From NodeB (report.etl):
9854 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:Flags=......S., SrcPort=60678, DstPort=1433, PayloadLen=0, Seq=4175055378, Ack=0, Win=8192 ( Negotiating scale factor 0x8 ) = 8192
9855 Idle (0) 10.0.0.11 10.190.127.70 WFP WFP:Packet Dropped - Filter Run-Time ID: 101249 (0x18B81), Layer Run-Time ID: 13 (0xD)
10047 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9554]Flags=......S., SrcPort=60678, DstPort=1433, PayloadLen=0, Seq=4175055378, Ack=0, Win=8192 ( Negotiating scale factor 0x8 ) = 8192
10049 Idle (0) 10.0.0.11 10.190.127.70 WFP WFP:Packet Dropped - Filter Run-Time ID: 101249 (0x18B81), Layer Run-Time ID: 13 (0xD)
10359 Idle (0) 10.0.0.10 10.0.0.11 TCP TCP:[SynReTransmit #9554]Flags=......S., SrcPort=60678, DstPort=1433, PayloadLen=0, Seq=4175055378, Ack=0, Win=8192 ( Negotiating scale factor 0x8 ) = 8192
10360 Idle (0) 10.0.0.11 10.190.127.70 WFP WFP:Packet Dropped - Filter Run-Time ID: 101249 (0x18B81), Layer Run-Time ID: 13 (0xD)
Do you see it? For every SYN packet sent, there’s a corresponding “WFP:Packet Dropped” event that follows! So, now we know what is going on and can confirm that WFP is dropping NodeA’s attempt to communicate with NodeB via a new inbound port. Note that we have the “what,” so now we need to figure out the “why,” for that let’s look at the WFPdiag output.
From NodeB (WFPDiag):
Looking at the packets and corresponding events from the netconnection log, we see the “Filter Run-Time ID” that triggered the drop. Using this ID we can get more data about the filter from the WFPDiag data. Opening the WFPDiag.cab file, you’ll find the wfpfilters.xml file. Opening this file, do a search for filter ID (in our example, 101249). Once you find the Filter ID, look for the "<name>" field between the “<item>” fields to find something like the following::
<item>
<filterKey>{67174099-bc59-4ca3-b1be-3e40992b6d13}</filterKey>
<displayData>
<name>Port Scanning Prevention Filter</name>
<description>This filter prevents port scanning.</description>
</displayData>
<flags/>
<providerKey>{decc16ca-3f33-4346-be1e-8fb4ae0f3d62}</providerKey>
<providerData>
<data>ffffffffffffffff</data>
<asString>........</asString>
</providerData>
<layerKey>FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD</layerKey>
<subLayerKey>{b3cdd441-af90-41ba-a745-7c6008ff2301}</subLayerKey>
<weight>
<type>FWP_UINT8</type>
<uint8>12</uint8>
</weight>
<filterCondition numItems="1">
<item>
<fieldKey>FWPM_CONDITION_FLAGS</fieldKey>
<matchType>FWP_MATCH_FLAGS_NONE_SET</matchType>
<conditionValue>
<type>FWP_UINT32</type>
<uint32>1</uint32>
</conditionValue>
</item>
</filterCondition>
<action>
<type>FWP_ACTION_CALLOUT_TERMINATING</type>
<calloutKey>FWPM_CALLOUT_WFP_TRANSPORT_LAYER_V4_SILENT_DROP</calloutKey>
</action>
<rawContext>0</rawContext>
<reserved/>
<filterId>101249</filterId>
<effectiveWeight>
<type>FWP_UINT64</type>
<uint64>13835058055315718144</uint64>
</effectiveWeight>
</item>
And there it is! Filter ID 101249 is none other than the “Port Scanning Prevention Filter” which is silently dropping the communication from NodeA! So, at this point, we’re almost done – we just need to understand the behavior of this filter and confirm what we’ve found.
Explanation:
The Port Scanning Prevention Filter is a Stealth Mode mechanism that is always active in the filtering platform providing additional protection to a node in a network even if the Firewall profiles have been turned off. (Reference this TechNet article regarding Stealth Mode in Windows Firewall with Advance Security)
When the “Port Scanning Prevention Filter” is triggered, it usually means that there is no process listening on the port, which WFP – by design – will block for security reasons. This is because when a connection is attempted on a port where there is no listener, WFP treats the packet as if it were coming from a “Port Scanner” and silently drops it. Had there been a listener, and the communication blocked due to either malformed packets or authentication, the dropped event would simply read “DROP” (not silent) and the WFP logging would indicate a different filter ID and name as well. This filter is a built in filter to Windows Firewall with Advanced Security (WFAS) which was introduced in Windows Vista & Windows Server 2008. The filter cannot be disabled through any supported method as this would break security and pose a considerably high security risk on a server/client machine.
“But what if I created a port rule to allow it?”
What if you really DID need traffic to come in on TCP port 1433? An explicit “allow” inbound rule on TCP 1433 would only allow the packet through if there was something listening for it, but because there is nothing listening to the port, the WFP filter will still drop the packet. To reiterate: creating an exemption to a port – without a listener – would still present a block by WFP on the logs.
Conclusion:
In our example, NodeA is attempting to connect on TCP Port 1433 (common SQL listener). So now, we need to confirm that NodeB has the proper executable for handling these requests configured to listen on TCP Port 1433 to determine if WFP is working correctly or simply misbehaving per our example. To do this, we need to examine the output of the following command which will allow us to see all TCP listeners on NodeB:
netstat -anob -p tcp
In our example, we see that there is no listener on 1433. Since we know that NodeA is attempting an SQL connection, we can dig even deeper by isolating the netstat output to see if SQL is listening.
TCP 0.0.0.0:6552 0.0.0.0:0 LISTENING 1824
[sqlservr.exe]
There you have it! SQL has been configured to listen on TCP Port 6552 and NOT 1433 (which is the default port for SQL communication). Since there is no listener on 1433, WFP treats the inbound connections as a “Port Scanner” and silently drops the packets.
-Luis Chinea (Platforms Networking Team)