Using Iptables 'recent' Module Against Bruteforce Attacks (Update)

Posted on June 17, 2011 by Hendrik Jäger

or: Being SIP-‘register’ flooded from several locations

Just recently I had to switch off my Asterisk PBX on this server due to distributed SIP Register Floods (or rather Bruteforce Login Attempts). Several thousands of “register” SIP packets were coming in in a few seconds, which, of course, my asterisk tried to cope with. But that was just too much for my server, load went through the ceiling and I had to switch asterisk off.

This weekend I took another attempt at making my server resistent against such attacks. It took some reading, some searching, but finally I came up with a solution pretty similar to the one stopping SSH bruteforce attempts. Below is what ‘iptables-save’ now comes up with, the relevant part only of course. Logging is limited to a few occurances per minute, but this could need some more tweaking.

# Generated by iptables-save v1.4.2 on Sat Dec 11 15:07:02 2010
*filter
:INPUT ACCEPT [2917:434824]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [2645:891090]
:sip-flood - [0:0]
:ssh-flood - [0:0]
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -m state --state NEW -j ssh-flood 
-A INPUT -i eth0 -p udp -m udp --dport 5060 -j sip-flood 
-A INPUT -i eth0 -p tcp -m tcp --dport 5060:5061 -m state --state NEW -j sip-flood 
-A sip-flood -m recent --set --name sip_throttle --rsource 
-A sip-flood -m recent --rcheck --seconds 60 --hitcount 20 --name sip_throttle --rsource -m limit --limit 1/min -j LOG --log-prefix "SIP bruteforce attempt: " 
-A sip-flood -m recent --rcheck --seconds 60 --hitcount 20 --name sip_throttle --rsource -j REJECT --reject-with icmp-port-unreachable 
-A ssh-flood -m recent --set --name ssh_throttle --rsource 
-A ssh-flood -m recent --rcheck --seconds 60 --hitcount 3 --name ssh_throttle --rsource -m limit --limit 1/min -j LOG --log-prefix "SSH bruteforce attempt: " 
-A ssh-flood -m recent --rcheck --seconds 60 --hitcount 3 --name ssh_throttle --rsource -j REJECT --reject-with icmp-port-unreachable 
COMMIT
# Completed on Sat Dec 11 15:07:02 2010

UPDATE

Regarding management of iptables rulesets, I often heard the recommendation to use ferm (http://ferm.foo-projects.org/), so finally I got around to rethinking the above setup and implementing it in ferm. The main goal of rethinking it was to make it more generic and more compact, i.e. ideally use the same rule for all ports that should be protected. This only works when the limits are universal and as it turned out, it seems they are for now.

  # ratelimit certain SYNs
  proto tcp   mod state   state new {
    mod multiport destination-ports '21,22,25,993,995,5060' @subchain synthrottle {
      mod recent name synspammer seconds 600 update DROP;
      mod hashlimit hashlimit-name synthrottle {
        hashlimit-mode 'srcip,dstip,dstport' hashlimit 5/min RETURN;
      }
      mod recent name synspammer set NOP;
      mod hashlimit hashlimit-name synlogthrottle {
        hashlimit-mode 'srcip,dstport' hashlimit 1/min {
          LOG log-prefix 'Excessive connection attempt: ';
        }
      }
      DROP;
    }
  }

  proto udp dport 31337 {
    mod recent name portknocking {
      rcheck hitcount 3 seconds 15 @subchain portknocking {
        LOG log-prefix 'synthrottling disabled: ';
        mod recent name synspammer remove REJECT;
      }
      set NOP;
    }
  }

Some remarks: - mod multiport helps keeping the ruleset small and the number of traversed rules low - using a subchain makes non-matching packets skip all those rules

You see that both the hashlimit and the recent module are used twice. Each one is used once in the actual process of blocking bruteforcers: Hashlimit is used to identify attackers by looking at srcip, dstip and dstport. When a srcip sends more packets to dstport on dstip than are allowed (5/min in that case) the srcip is added to the recent list ‘synspammer’. This list is also the first to be checked when a new packet comes in on a protected port to see if the srcip is supposed to be blocked. Hashlimit is used again to throttle logging of excessive and thus blocked connection attempts to 1 per minute per sourceip and destinationport. Recent is used again in the (optional of course) rules which allow experienced users to disable the throttling should they activate it coincidentally. 3 Packets to UDP-port 31337 in 15 seconds remove the senders IP from the synthrottling list. I called it “portknocking” for the lack of a better name, suggestions are welcome.