SSH Filtering with IPTables
Introduction
After a recent rise in the amount of SSH attacks I decided to have a look at other methods of blocking SSH attacks.
AutoBlock
AutoBlock is enabled by default on SME9 and later. By design only IP outside your local network will be blocked if too many attempts are done.
Default values
AutoBlockTime=900 # 900 seconds (15 minutes). AutoBlockTries=4 # meaning that 3 Tries are allowed, the fourth try is blocked. AutoBlock=disabled # default for SME Server 8 AutoBlock=enabled # default for SME Server 9
However there is no whitelist, you can easily lock you out.
DenyHosts
DenyHosts works well:
https://wiki.contribs.org/Denyhosts
However, it was sending me a lot of mails. Yes, I could disable them.
However, it has to check the logs and find failed logins and then create a list for ssh to check against. So it will allow at least one failed connection. It is, quite lightweight as it will update a simple plain text file called by /etc/hosts.deny on every ssh connection.
I wanted something a bit quicker that would bulk block a lot of IPs immediately.
Fail2ban
Fail2ban works as well:
https://wiki.contribs.org/Fail2ban
However, it needs 3 attempts and required quite a bit of processing so can be a bit cumbersome.
What I really wanted was to block some IPs outright using GeoIP blocking.
Fail2ban can do this as per this:
https://thecustomizewindows.com/2016/11/fail2ban-geoip-action-script-block-ssh-country/
However, I wanted a something a bit lighter and faster and an instant block. The above link show you how to create a script that you can use with hosts/allow to block with GeoIP
Xtables
There are some xtables RPMs floating about that work with GeoIP v1 DBs but not sure about v2 DBs. Needs investigation
07/02/20109 - These are in the process of being imported. They will work with GeoIP2.
smeserver-xt_geoip xtables-addons
They should be in smetest shortly.
hosts.allow
This approach is very brute force and ignorance. You are highly likely to lock yourself out, so be prepared. Preferably keep an extra terminal open and logged in as a backup.
Make sure other SSH blocking features like denyhosts etc are disabled
mkdir -p /etc/e-smith/templates-custom/etc/hosts.allow
cp /etc/e-smith/templates/etc/hosts.allow/sshd /etc/e-smith/templates-custom/etc/hosts.allow
Open the custom template with your favourite editor.
Remove any other lines and then add this line where a.b.c.d is the IP
sshd: a.b.c.d: allow
You can add more than one address, and subnets too - there is plenty of information online about this.
sshd: a.b.c.d w.x.y.: allow
The only down side is it leaves a lot of mess in your messages log and so far I can't find out how to shift the messages elsewhere.
It is very effective though.
SSH Filter with GeoIP blocking
Another approach is one I found here originally:
https://www.axllent.org/docs/view/ssh-geoip
However, CentOS does not use aclexec.
I looked for a replacement and found this site, and a relevant comment below
https://tecadmin.net/allow-server-access-based-on-country/
"For all CentOS users, spawn or aclexec does not work, the hint is already given by using iptables to block the user. The iptables command given appends (-A) so the connection might still go through, to really block the IP you have to insert (-I) the block rule at rule #1. You can use my altered script for a working CentOS/RHEL version: https://github.com/chiel1980/scripts/blob/master/ipfilter.sh"
So I grabbed a copy of the script but found I had to do a little work for it to run with SME.
Installation
Here is how to install the geoip blocking script.
Prerequisites
OK, running GeoIP2 databases is a prerequisite. Please see smeserver-geoip2 here https://wiki.contribs.org/GeoIP
Make sure you disable denyhosts so it doesn't interfere with this script in hosts.allow
Installing
Make sure you can get results with the geoiplookup tool
Get the main script:
wget https://www.reetspetit.com/Other/sshfilter.sh -O /usr/local/bin/sshfilter.sh
chmod 0755 /usr/local/bin/sshfilter.sh
Edit the file with your favourite editor.
Add the countries you want to ALLOW in:
ALLOW_COUNTRIES
They are currently set to GB ES FR but you can use any country code/s.
Create a masq iptables fragment to handle the blocks
mkdir -p /etc/e-smith/templates-custom/etc/rc.d/init.d/masq/ touch /etc/e-smith/templates-custom/etc/rc.d/init.d/masq/40sshFilter
Add this:
# A blacklist chain for sshFilter /sbin/iptables --new-chain BLOCKDYN /sbin/iptables -A INPUT -j BLOCKDYN
Create a hosts.allow custom fragment as above with the following contents:
sshd: ALL : spawn /usr/local/bin/sshfilter.sh %a %d
Now we can expand the templates and restart the masq service:
expand-template /etc/rc.d/init.d/masq expand-template /etc/hosts.allow service masq restart
Now you can look at iptables to see your handiwork
iptables -L BLOCKDYN
Notes
Testing - please see the comments in the script for how to test.
/usr/local/bin/sshfilter.sh 1.2.3.4 ssh DE BLOCKDYN
echo "" | /usr/local/bin/sshfilter.sh 8.8.8.8 ssh DE BLOCKDYN
Issues
Logging.
All the logging goes to /var/log/secure. Errors should really go elsewhere. Needs some thought. See my comments:
# This will log to /var/log/secure LOGDENY_FACILITY="authpriv.info" # This should go to /var/log/messages but doesn't. Need to figure that out LOGDENY_FACILITY_ERR="authpriv.error"
IPTables
The table can get big quickly.
It may be worth having running an iptables flush from cron periodically
You can do it manually
iptables -F BLOCKDYN
It may be worth looking at adding a specific AllowHosts section in the chain, or somewhere in masq to Allow Specific hosts, but block the rest of a country.