Protect your server using fail2ban#
Created: 2019-02-07
While reading the system journal of my server, I noticed a bunch of evil looking entries and finally found in the Python tool fail2ban a satisfying but not an overall answer to the problem.
The system journal can be inspected by:
$ sudo journalctl -r
Feb 07 14:29:45 dummy sshd[763]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=XXX.XX.X.XXX user=root
Feb 07 14:29:45 dummy sshd[764]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=YY.YYY.YY.YY user=root
Feb 07 14:29:47 dummy sshd[760]: error: PAM: Authentication failure for root from XXX.XX.X.XXX
Feb 07 14:29:47 dummy sshd[758]: error: PAM: Authentication failure for root from YY.YYY.YY.YY
Feb 07 14:29:48 dummy sshd[765]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=YY.YYY.YY.YY user=root
Feb 07 14:29:48 dummy sshd[766]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=XXX.XX.X.XXX user=root
Feb 07 14:29:50 dummy sshd[758]: error: PAM: Authentication failure for root from YY.YYY.YY.YY
Feb 07 14:29:50 dummy sshd[760]: error: PAM: Authentication failure for root from XXX.XX.X.XXX
Feb 07 14:29:50 dummy sshd[767]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=YY.YYY.YY.YY user=root
Feb 07 14:29:51 dummy sshd[768]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=XXX.XX.X.XXX user=root
Feb 07 14:29:52 dummy sshd[758]: error: PAM: Authentication failure for root from YY.YYY.YY.YY
Feb 07 14:29:52 dummy sshd[758]: Received disconnect from YY.YYY.YY.YY port 58773:11: [preauth]
Feb 07 14:29:52 dummy sshd[758]: Disconnected from authenticating user root YY.YYY.YY.YY port 58773 [preauth]
Feb 07 14:29:52 dummy sshd[760]: error: PAM: Authentication failure for root from XXX.XX.X.XXX
Feb 07 14:29:53 dummy sshd[760]: Postponed keyboard-interactive for root from XXX.XX.X.XXX port 19193 ssh2 [preauth]
Feb 07 14:29:53 dummy sshd[769]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=XXX.XX.X.XXX user=root
Feb 07 14:29:56 dummy sshd[760]: error: PAM: Authentication failure for root from XXX.XX.X.XXX
Feb 07 14:29:56 dummy sshd[760]: Failed keyboard-interactive/pam for root from XXX.XX.X.XXX port 19193 ssh2
Feb 07 14:29:56 dummy sshd[760]: Postponed keyboard-interactive for root from XXX.XX.X.XXX port 19193 ssh2 [preauth]
Two hosts (later I noticed a few more),
lets call them XXX.XX.X.XXX
and YY.YYY.YY.YY
for now,
are permanently trying to log in to my server as root.
Using an arbitrary IP-Address lookup service, I was told be attacked from hosts in Asia. The country was reported as well, but it does not matter for this blog post. In my opinion the worth of this information is doubtful anyways.
But for now, I write about what I did and what prevented greater damage so far:
A good decision at server setup was to only permit logins via
public-key cryptography
and not passwords.
Especially root
should never be able to login by a plain ssh
command!
To achieve this,
the following entries are set in /etc/ssh/sshd_config
:
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
This is in my opinion the most important layer of defense against brute force attacks. But as my system journal reveals, this is by far not enough. I don’t want my server to waste time with brute force attacks. It should simply ignore any communication with them.
A promising approach without writing black- or whitelists on my own is the Python software fail2ban. Like the name suggests, too many failed login attempts (= brute force attacks) automatically result in a permanent ban from my server. In general I consulted three sources for the fail2ban setup:
First one has to install the software. openSUSE makes this task pretty comfortable by typing
sudo zypper in fail2ban
Then I edited as root
the configuration file /etc/fail2ban/jail.local
:
# Do all your modifications to the jail's configuration in jail.local!
[DEFAULT]
bantime = 1d
# SSH servers
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
and finally started the already available service:
sudo systemctl start fail2ban.service
Now each suspicious login behavior will result in a one day 1d
ban.
To verify this theory,
there are several ways to check.
The first method is to read the fail2ban log:
$ sudo cat /var/log/fail2ban.log
2019-02-04 16:39:40,379 fail2ban.server [2885]: INFO --------------------------------------------------
2019-02-04 16:39:40,379 fail2ban.server [2885]: INFO Starting Fail2ban v0.10.3.fix1
2019-02-04 16:39:40,385 fail2ban.database [2885]: INFO Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2019-02-04 16:39:40,386 fail2ban.database [2885]: WARNING New database created. Version '2'
2019-02-07 14:31:02,652 fail2ban.server [2885]: INFO Shutdown in progress...
2019-02-07 14:31:02,652 fail2ban.server [2885]: INFO Stopping all jails
2019-02-07 14:31:02,652 fail2ban.database [2885]: INFO Connection to database closed.
2019-02-07 14:31:02,652 fail2ban.server [2885]: INFO Exiting Fail2ban
2019-02-07 14:31:02,737 fail2ban.server [907]: INFO --------------------------------------------------
2019-02-07 14:31:02,737 fail2ban.server [907]: INFO Starting Fail2ban v0.10.3.fix1
2019-02-07 14:31:02,739 fail2ban.database [907]: INFO Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2019-02-07 14:31:02,740 fail2ban.jail [907]: INFO Creating new jail 'sshd'
2019-02-07 14:31:02,747 fail2ban.jail [907]: INFO Jail 'sshd' uses systemd {}
2019-02-07 14:31:02,748 fail2ban.jail [907]: INFO Initiated 'systemd' backend
2019-02-07 14:31:02,748 fail2ban.filter [907]: INFO maxLines: 1
2019-02-07 14:31:02,773 fail2ban.filtersystemd [907]: INFO [sshd] Added journal match for: '_SYSTEMD_UNIT=sshd.service + _COMM=sshd'
2019-02-07 14:31:02,773 fail2ban.filter [907]: INFO maxRetry: 5
2019-02-07 14:31:02,774 fail2ban.filter [907]: INFO encoding: UTF-8
2019-02-07 14:31:02,774 fail2ban.actions [907]: INFO banTime: 86400
2019-02-07 14:31:02,774 fail2ban.filter [907]: INFO findtime: 600
2019-02-07 14:31:02,776 fail2ban.jail [907]: INFO Jail 'sshd' started
2019-02-07 14:31:02,796 fail2ban.filter [907]: INFO [sshd] Found YY.YYY.YY.YY - 2019-02-07 14:21:03
2019-02-07 14:31:02,797 fail2ban.filter [907]: INFO [sshd] Found XXX.XX.X.XXX - 2019-02-07 14:21:04
... many many lines like this ...
2019-02-07 14:31:02,976 fail2ban.actions [907]: NOTICE [sshd] Ban YY.YYY.YY.YY
2019-02-07 14:31:03,016 fail2ban.actions [907]: NOTICE [sshd] Ban XXX.XX.X.XXX
2019-02-07 14:31:03,022 fail2ban.actions [907]: WARNING [sshd] YY.YYY.YY.YY already banned
2019-02-07 14:31:03,022 fail2ban.actions [907]: WARNING [sshd] XXX.XX.X.XXX already banned
...
Et voilà,
XXX.XX.X.XXX
and YY.YYY.YY.YY
misbehaved and were banned! :smile:
To get even more trust and understanding in the fail2ban mechanism,
one can take a look at
iptables,
the system tool,
where fail2ban adds appropriate entries:
$ sudo iptables -L
...
Chain f2b-sshd (1 references)
target prot opt source destination
REJECT all -- YY.YYY.YY.YY anywhere reject-with icmp-port-unreachable
REJECT all -- XXX.XX.X.XXX anywhere reject-with icmp-port-unreachable
...
My system is of no such importance, that I dare write about this attack to learn from it. Maybe (and in case of critical systems hopefully) other system administrators know better and can teach me how to cope with such a delicate and mean situation.
All in all I hope not to be part of a botnet or similar right now and that attackers no longer find my sever to be a patient listener :wink: