Bug #13918
openICMP timestamp requests are passed by states created from ICMP echo requests if they use the same ID
0%
Description
ICMP timestamp requests with the same identifier of a previously allowed ICMP echo request are also allowed. This is due to the ICMP timestamp request matching the ICMP echo request state that exists.
This issue seems to have existed for some time:
https://marc.info/?l=openbsd-tech&m=117487638116535
https://nvd.nist.gov/vuln/detail/CVE-1999-0524
- Create a rule on the firewall allowing ICMP echo requests, then another blocking all ICMP:
pass in quick on $ADMIN inet proto icmp from any to any icmp-type echoreq ridentifier 1675111483 keep state label "USER_RULE" label "id:1675111483"
block in quick on $ADMIN inet proto icmp from any to any ridentifier 1675111494 label "USER_RULE" label "id:1675111494" - Using
nping
, send an echo request with a specified ID, then send the timestamp request:
nping --icmp --icmp-id 19397 10.0.5.1
nping --icmp --icmp-type 13 --icmp-id 19397 10.0.5.1
Related issues
Updated by Marcos M almost 2 years ago
- Related to Bug #13652: Inconsistent behavior filtering ICMP traffic added
Updated by Jim Pingle almost 2 years ago
- Subject changed from ICMP timestamp requests are not dropped to ICMP timestamp requests are passed by states created from ICMP echo requests if they use the same ID
- Priority changed from Normal to Low
This just seems to be part of how pf tracks state for ICMP currently. Given that ICMP is a "stateless" protocol it has no choice but to play a bit loose with what is or isn't a related packet.
Updated by Reid Linnemann almost 2 years ago
- Assignee set to Reid Linnemann
pf's state table is keyed by a structure that is defined with TCP/UDP in mind and includes a source and destination port. At this time, the ports are overloaded to identify the icmpid, and the icmp type is not used in the key at all. I think the proper solution to this is to change the structure definition so that it has the common destination addresses, address family, and protocol as members and replace the tcp/udp ports with a union that has a specific meaning per protocol, and put both the icmpid and icmp_type into that union for icmp proto keys. There would be no binary incompatible change, but some attention may need to be made to pfctl's state listing.
Updated by Serge Caron almost 2 years ago
First, thanks to Marcos for providing a simple test.
I have the following FLOATING rules repeated for every interface on the firewall to handle the TimeStamp/Address Mask/Information requests/replies and allow other ICMP traffic:
pass quick on em1.66 inet proto icmp from <ISPRouterIPAdresses> to any icmp-type unreach keep state label "USER_RULE: Allow ICMP reports from router (Don't know which ..." ridentifier 1668177720
block drop quick on em1.66 inet from <UnsolicitedISPTrafic> to any label "USER_RULE: Discard unsollicited trafic from ISP router" ridentifier 1668177846
pass quick on em1.66 inet proto icmp all icmp-type echoreq keep state label "USER_RULE: Allow basic diagnostics" ridentifier 1668015336
pass log on em1.66 inet proto icmp all icmp-type echorep keep state label "USER_RULE: Allow basic diagnostics (deferred)" ridentifier 1668015427
match log on em1.66 inet proto icmp all icmp-type inforep label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
match log on em1.66 inet proto icmp all icmp-type inforeq label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
match log on em1.66 inet proto icmp all icmp-type maskrep label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
match log on em1.66 inet proto icmp all icmp-type maskreq label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
match log on em1.66 inet proto icmp all icmp-type timerep label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
match log on em1.66 inet proto icmp all icmp-type timereq label "USER_RULE: Log bad ICMP (trafic match only)" ridentifier 1669644959
block drop log quick on em1.66 inet proto icmp all icmp-type inforeq label "USER_RULE: Discard any and all ICMP Timestamp, Address Mask..." ridentifier 1667827889
block drop log quick on em1.66 inet proto icmp all icmp-type maskreq label "USER_RULE: Discard any and all ICMP Timestamp, Address Mask..." ridentifier 1667827889
block drop log quick on em1.66 inet proto icmp all icmp-type timereq label "USER_RULE: Discard any and all ICMP Timestamp, Address Mask..." ridentifier 1667827889
block drop out log on em1.66 inet proto icmp all icmp-type inforep label "USER_RULE: Discard any and all ICMP Outgoing Timestamp, Addr..." ridentifier 1667764490
block drop out log on em1.66 inet proto icmp all icmp-type maskrep label "USER_RULE: Discard any and all ICMP Outgoing Timestamp, Addr..." ridentifier 1667764490
block drop out log on em1.66 inet proto icmp all icmp-type timerep label "USER_RULE: Discard any and all ICMP Outgoing Timestamp, Addr..." ridentifier 1667764490
pass log quick on em1.66 inet proto icmp all keep state label "USER_RULE: Accept any other ICMP trafic" ridentifier 1675147686
When TimeStamp requests are allowed regardless of the blocking rule, neither the match or the block rules are ever triggered for the TimeStamp reply.
It is as if the reply is not handled by pf, regardless of the interface used.
This may or may not be the same behavior. The above rules are created to avoid these request/replies crossing ANY subnet within the firewall: they obviously fail ;-)