Fail2Ban Ubuntu 22.04
What is Fail2Ban?
https://www.digitalocean.com/community/tutorials/how-to-protect-ssh-with-fail2ban-on-ubuntu-22-04
Fail2Ban is a utility that monitors logs and if suspicious activity is detected, it bans the IP using iptables. It is highly customizable for many default products and custom products. It runs as service on startup and can keep track of bad actors over many months of their attack.
Why is this Important?
(1:1444)# ./count_auth_types.sh
Range Sep 25 20:47:16 - Oct 8 07:06:17
Count Reason
13375 Invalid User
525 Unable to negotiate
1371 Timeout before authentication
0 Invalid user password
3629 Connection closed
0 Accepted Password
12 Accepted Public Key
So, in a 6 day period we had over 35k different attacks on ssh.
Here is the script that parsed out that info:
#!/bin/bash
# Default start date from auth.log
start_date=$(head -1 /var/log/auth.log | awk '{print $1,$2,$3}')
end_date=$(tail -1 /var/log/auth.log | awk '{print $1,$2,$3}')
# Check if there are any gzipped logs, if yes, then update the start date
if [ -n "$(ls /var/log/auth.log.*.gz 2>/dev/null)" ]; then
gz_start_date=$(zcat /var/log/auth.log.*.gz | head -1 | awk '{print $1,$2,$3}')
if [ "$gz_start_date" ]; then
start_date=$gz_start_date
fi
fi
echo "Range $start_date - $end_date"
echo -e "Count\tReason"
# Function to compute and print the count for a given regex pattern and reason
count_pattern() {
local pattern=$1
local reason=$2
# Count in current log
local count=$(grep -E "$pattern" /var/log/auth.log | wc -l)
# Count in gzipped logs, if they exist
if [ -n "$(ls /var/log/auth.log.*.gz 2>/dev/null)" ]; then
local gz_count=$(zgrep -E "$pattern" /var/log/auth.log.*.gz | wc -l)
count=$((count + gz_count))
fi
printf "%d\t%s\n" "$count" "$reason"
}
count_pattern 'Invalid user' "Invalid User"
count_pattern 'Unable to negotiate' "Unable to negotiate"
count_pattern 'Timeout before authentication' "Timeout before authentication"
count_pattern 'Invalid user password' "Invalid user password"
count_pattern 'Connection closed' "Connection closed"
count_pattern 'Accepted password' "Accepted Password"
count_pattern 'Accepted publickey' "Accepted Public Key"
Install Fail2Ban
apt update
apt install fail2ban
Configure Basics
You want to edit the /etc/fail2ban/jail.local by making a copy of /etc/fail2ban/jail.conf first.
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Every service is enabled = false by default and then you add an enabled = true for the services you want to monitor.
The [DEFAULT] section includes things like timers and then you configure the other services as needed. The disabled services can be deleted from your conf.
Start by updating the following, but read through the rest for other options:
[DEFAULT]
bantime.increment = true
bantime.rndtime = 300
bantime.maxtime = 604800
bantime = 60m
findtime = 10m
maxretry = 1
Configure Services
DEFAULT will not actually protect you though. Next you need to enable services. I use sshd, and want it protected, so I am going to modify the sshd seciont and add a custom service at the same time:
SSH
[sshd]
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode = normal
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
Here is the custom service:
[sshd-not22]
enabled = true
port = 0:65535
excludeports = 22,80,443
filter = sshd-not22
logpath = /var/log/auth.log
maxretry = 1
We want a scanner to be banned for touching any port that isn’t 22,80,443. what about icmp or udp ?
I need to define this service, and it’s done here:
vim /etc/fail2ban/filter.d/sshd-not22.conf
[Definition]
failregex = ^.*Did not receive identification string from <HOST> port [0-9]*$
^.*sshd\[.*\]: Invalid user .* from <HOST> port [0-9]*$
^.*sshd\[.*\]: Unable to negotiate with <HOST> port [0-9]*: no matching host key type found. Their offer: ssh-rsa,ssh-dss \[preauth\]$
^.*sshd\[.*\]: fatal: Timeout before authentication for <HOST> port [0-9]*$
ignoreregex =
NGINX
I am using 2 of the default NGINX protections, the brute force guesser and the fuzzer.
[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
maxretry = 2
Other Services
I’m not using any other services, so I did not add “enabled = true” to anything else.
Fail2ban Service Manipulation
Enable Service on Reboot
You might want to test everything before making it permanent on every boot:
systemctl enable fail2ban
Restart the Service
systemctl restart fail2ban
Service Status
systemctl status fail2ban.service
○ fail2ban.service - Fail2Ban Service
Loaded: loaded (/lib/systemd/system/fail2ban.service; disabled; vendor preset: enabled
Active: inactive (dead)
Docs: man:fail2ban(1)
View Custom Service
The status of some service must match the name you called it when creating the custom service. In my example sshd-not22 was the custom service name.
(1:1404)# fail2ban-client status sshd-not22
Status for the jail: sshd-not22
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 0
|- Total banned:
Display Banned IP
In my settings the default ban is for 60 minutes, but this doubles if they try again within a 10 minute window up to the max. So these are timers that will fall off eventually. You can see the current bans looking at iptables:
(1:1449)# iptables -S | grep f2b
-N f2b-sshd
-N f2b-sshd-not22
-A INPUT -p tcp -m multiport --dports 0:65535 -j f2b-sshd-not22
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A f2b-sshd -s 115.95.180.244/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 24.199.119.46/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 128.199.182.19/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 146.190.60.250/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 182.16.245.79/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 165.154.147.47/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 43.155.163.36/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 170.106.196.12/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 62.99.74.174/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 165.22.127.104/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 170.64.187.53/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -s 170.64.174.82/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -j RETURN
-A f2b-sshd-not22 -s 115.95.180.244/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 24.199.119.46/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 128.199.182.19/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 182.16.245.79/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 165.154.147.47/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 43.155.163.36/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 170.106.196.12/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 62.99.74.174/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -s 76.21.196.191/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd-not22 -j RETURN
View Ban Logs
Ban logs explain a bit more of what the attacker was doing that triggered the ban.
cat /var/log/fail2ban.log
- Found = we saw you do something, but haven’t banned you yet
- Ban = you just got banned
- Retore Ban = service restarted, so we are reloading all bans