Mitigate attacks with iptables, fail2ban and ipset

In this short article, we will describe useful steps to prevent attacks and other malicious attempts.

Assuming we do the configuration on a Debian-based system.


First of all, we need to install the necessary tools
apt-get install ipset iptables-persistent fail2ban

Let’s start adding some rules to iptables.

Drop invalid packets to the mangle table
iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP

Drop TCP packets that are new and are not SYN
iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

Drop SYN packets with suspicious MSS value
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

Block packets with bogus TCP flags
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

SSH brute-force protection
iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --set
iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 -j DROP

Protect against port scanning
iptables -N port-scanning 
iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN 
iptables -A port-scanning -j DROP

Save the rules to the iptables start-up config
/sbin/iptables-save > /etc/iptables/rules

Let’s take a look at fail2ban

Enable fail2ban on startup and start the service
systemctl enable fail2ban
systemctl start fail2ban

Now we need to setup ipset and his blacklist

Create blacklist with ipset utility (once)
ipset create blacklist hash:ip hashsize 4096

At this stage we have ipset blacklist create.

It’s time to set more iptables rules to match with blacklist and drop traffic
iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP

Don’t forget to save the rules to the start-up config

/sbin/iptables-save > /etc/iptables/rules

Now you can manually fill the blacklist

Take a look in /var/log/fail2ban.log to see who attempted to get access to your server.

tail -40 /var/log/fail2ban.log

Add a specific IP address to your newly created blacklist
ipset add blacklist <write here the ip you want block>

That’s it. If you want to check which IP addresses are on your list
ipset list blacklist

At this point, we have decent security for common script kiddies. But if we want to have more view on our connections we need to use the ss command:

Usage: ss [ OPTIONS ]
 ss [ OPTIONS ] [ FILTER ]
 -h, --help this message
 -V, --version output version information
 -n, --numeric don't resolve service names
 -r, --resolve resolve host names
 -a, --all display all sockets
 -l, --listening display listening sockets
 -o, --options show timer information
 -e, --extended show detailed socket information
 -m, --memory show socket memory usage
 -p, --processes show process using socket
 -i, --info show internal TCP information
 -s, --summary show socket usage summary
 -b, --bpf show bpf filter socket information
 -E, --events continually display sockets as they are destroyed
 -Z, --context display process SELinux security contexts
 -z, --contexts display process and socket SELinux security contexts
 -N, --net switch to the specified network namespace name

-4, --ipv4 display only IP version 4 sockets
 -6, --ipv6 display only IP version 6 sockets
 -0, --packet display PACKET sockets
 -t, --tcp display only TCP sockets
 -S, --sctp display only SCTP sockets
 -u, --udp display only UDP sockets
 -d, --dccp display only DCCP sockets
 -w, --raw display only RAW sockets
 -x, --unix display only Unix domain sockets
 -f, --family=FAMILY display sockets of type FAMILY
 FAMILY := {inet|inet6|link|unix|netlink|help}

-K, --kill forcibly close sockets, display what was closed
 -H, --no-header Suppress header line

-A, --query=QUERY, --socket=QUERY
 QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]

-D, --diag=FILE Dump raw information about TCP sockets to FILE
 -F, --filter=FILE read filter information from FILE
 FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
 STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}
 TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}
 connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
 synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
 bucket := {syn-recv|time-wait}
 big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}

Check who is connected at the moment to your server with ipv4
ss -t4 state established = check who is connected at the moment to your server with ipv4
5 3 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments