Linux – Has the filtering of all kinds of TCP attacks using iptables become obsolete as they get filtered elsewhere or something else

iptableslinuxnetworkingSecuritytcp

Background

I am on Debian 10 Buster. I started running a Tor relay on my home IP address. A dedicated full-fledged server is probably not the most energy efficient way, but I want to try it out. And since I stopped running Bitcoin daemon, there is plenty of traffic available. In spite, I do have a purely networking question, from past experience I know it does not belong to our sister site dedicated to this topic.


Research

This morning I came across a very old answer on ServerFault, and since I was curious, I applied those rules, see below a complete list. I have added some more rules I have found somewhere else. Simplified it and made some nice structure of it.

I'd like to ask if the following rules can have any measurable results now in 2019 with kernel 4.19.0-2-amd64?


From the iptables' IPv4 file – /etc/iptables/rules.v4:

--append INPUT --proto all --fragment                                --jump DROP    --match comment --comment "all fragmented packets"
--append INPUT --proto all --match state --state INVALID             --jump DROP    --match comment --comment "all invalid packets"
--append INPUT --proto icmp --match u32 ! --u32 "0x4&0x3fff=0x0"     --jump DROP    --match comment --comment "icmp fragmented packets"
--append INPUT --proto icmp --match length --length 1492:65535       --jump DROP    --match comment --comment "icmp oversized unfragmented packets"
--append INPUT --proto tcp ! --syn --match state --state NEW         --jump DROP    --match comment --comment "new non-syn packets"
--append INPUT --proto tcp --tcp-flags  ALL  NONE                    --jump DROP    --match comment --comment "NULL scan"
--append INPUT --proto tcp --tcp-flags  ALL  ALL                     --jump DROP    --match comment --comment "Xmas scan"
--append INPUT --proto tcp --tcp-flags  ALL  FIN,URG,PSH             --jump DROP    --match comment --comment "stealth scan"
--append INPUT --proto tcp --tcp-flags  ALL  SYN,RST,ACK,FIN,URG     --jump DROP    --match comment --comment "pscan 1"
--append INPUT --proto tcp --tcp-flags  SYN,FIN  SYN,FIN             --jump DROP    --match comment --comment "pscan 2"
--append INPUT --proto tcp --tcp-flags  FIN,RST  FIN,RST             --jump DROP    --match comment --comment "pscan 3"
--append INPUT --proto tcp --tcp-flags  SYN,RST  SYN,RST             --jump DROP    --match comment --comment "SYN-RST scan"
--append INPUT --proto tcp --tcp-flags  ACK,URG  URG                 --jump DROP    --match comment --comment "URG scans"
--append INPUT --proto tcp --tcp-flags  ALL  SYN,FIN                 --jump DROP    --match comment --comment "SYN-FIN scan"
--append INPUT --proto tcp --tcp-flags  ALL  URG,PSH,FIN             --jump DROP    --match comment --comment "nmap Xmas scan"
--append INPUT --proto tcp --tcp-flags  ALL  FIN                     --jump DROP    --match comment --comment "FIN scan"
--append INPUT --proto tcp --tcp-flags  ALL  URG,PSH,SYN,FIN         --jump DROP    --match comment --comment "nmap-id scan"

Thus far, after 0.5 days, I can only see rules #2 and #5 catching some packets:

2       67 13972 DROP       all  --  any    any     anywhere             anywhere             state INVALID /* all invalid packets */
5      158 81683 DROP       tcp  --  any    any     anywhere             anywhere             tcp flags:!FIN,SYN,RST,ACK/SYN state NEW /* new non-syn packets */

after 1.25 days, still catching only on the one TCP rule and on the INVALID one:

2      178 26785 DROP       all  --  any    any     anywhere             anywhere             state INVALID /* all invalid packets */
5      467  241K DROP       tcp  --  any    any     anywhere             anywhere             tcp flags:!FIN,SYN,RST,ACK/SYN state NEW /* new non-syn packets */

after 7 days, still catching only on the one TCP rule and on the INVALID one + I see a lot of DROPs on the INPUT chain in general, I did not notice that before:

Chain INPUT (policy DROP 62772 packets, 17M bytes)
2     3475  355K DROP       all  --  any    any     anywhere             anywhere             state INVALID /* all invalid packets */
5     2459 1324K DROP       tcp  --  any    any     anywhere             anywhere             tcp flags:!FIN,SYN,RST,ACK/SYN state NEW /* new non-syn packets */

Question

Are the other rules considered obsolete as they get filtered elsewhere or something else?

Best Answer

To complete @roaima's answer, and really just because you wanted all the tiny details, here is the reason those two rules below can't match on most configurations:

--append INPUT --proto all --fragment                                --jump DROP

and

--append INPUT --proto icmp --match u32 ! --u32 "0x4&0x3fff=0x0"     --jump DROP

--match u32 ! --u32 "0x4&0x3fff=0x0" is just a convoluted low-level method to write --fragment except maybe it includes the MF flag in addition: the fragment offset (+ flag MF) is the u32 word at offset 4 in the IP packet (0x4), in its lowest bits part (&0x3fff): a non null value is equivalent to having a fragment (or announcing more fragments).

But because there's (at least) --match state the module nf_conntrack is loaded which in turn requires the module nf_defrag_ipv4. This defragmentation is done at PREROUTING hook priority -400, thus not allowing anything after to ever see fragments but just a newly built reassembled packet. Later kernels permit to load the raw table at a lower priority:

# modinfo -p iptable_raw
raw_before_defrag:Enable raw table before defrag (bool)

thus allowing to see those packets, but only in the raw table (where obviously conntrack can't be used).

Now also to be really thorough, contrary to my previous example, by default Debian buster won't use ip_tables or any iptable_* modules, because for iptables, Debian buster uses by default iptables-nft which is iptables translated over nftables but still sometimes using iptables-extensions' xt_* modules.

UPDATE: This will still allow the u32 module to be used and be working, but will prevent to try and alter the rule via nft (eg can't be saved then restored, and emulation for now would always choose priority -300 for the chain raw/PREROUTING).

root@buster-amd64:~# update-alternatives --display iptables|head -3
iptables - auto mode
  link best version is /usr/sbin/iptables-nft
  link currently points to /usr/sbin/iptables-nft


# iptables -A INPUT -p udp --fragment -j DROP
# iptables -A INPUT -p icmp --match u32 ! --u32 "0x4&0x3fff=0x0" -j DROP
# iptables -S INPUT
-P INPUT ACCEPT
-A INPUT -p udp -f -j DROP
-A INPUT -p icmp -m u32 ! --u32 "0x4&0x3fff=0x0" -j DROP
# nft --debug=netlink list ruleset -a
ip filter INPUT 4 
  [ meta load l4proto => reg 1 ]
  [ cmp eq reg 1 0x00000011 ]
  [ payload load 2b @ network header + 6 => reg 1 ]
  [ bitwise reg 1 = (reg=1 & 0x0000ff1f ) ^ 0x00000000 ]
  [ cmp neq reg 1 0x00000000 ]
  [ counter pkts 0 bytes 0 ]
  [ immediate reg 0 drop ]

ip filter INPUT 5 4 
  [ meta load l4proto => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ match name u32 rev 0 ]
  [ counter pkts 4 bytes 4096 ]
  [ immediate reg 0 drop ]

table ip filter { # handle 5
    chain INPUT { # handle 1
        type filter hook input priority 0; policy accept;
        meta l4proto udp ip frag-off & 8191 != 0 counter packets 0 bytes 0 drop # handle 4
        meta l4proto icmp # u32 ! "0x4&0x3fff=0x0" counter packets 4 bytes 4096 drop # handle 5
    }

    chain FORWARD { # handle 2
        type filter hook forward priority 0; policy accept;
    }

    chain OUTPUT { # handle 3
        type filter hook output priority 0; policy accept;
    }
}

Note that rule handle #5 has a comment placed before u32, not because it's not working, but because it can't be handled by native nft. Bytecode dump won't show the actual payload check which is stored elsewhere but will behave as intended, and the counter will increase when an actual fragment is received and dropped.

Related Question