Preventing Brute Force Attacks With BlockHosts On Debian Etch

Version 1.0
Author: Falko Timme

In this article I will show how to install and configure BlockHosts on a Debian Etch system. BlockHosts is a Python tool that observes login attempts to various services, e.g. SSH, FTP, etc., and if it finds failed login attempts again and again from the same IP address or host, it stops further login attempts from that IP address/host. By default, BlockHosts supports services that use TCP_WRAPPERS, such as SSH, i.e. services, that use /etc/hosts.allow or /etc/hosts.deny, but it can also block other services using iproute or iptables.

This document comes without warranty of any kind! I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

I have tested BlockHosts on a Debian Etch system.

I will show you how to to use it with a service that uses /etc/hosts.allow or /etc/hosts.deny (sshd) and with a service that doesn't use TCP_WRAPPERS, e.g. Debian's ProFTPd package. Services that don't use /etc/hosts.allow or /etc/hosts.deny can be blocked by iproute or iptables.

I assume that OpenSSH and ProFTPd are both properly installed and working on your system.

 

2 Installing BlockHosts

As BlockHosts is written in Python, we must install Python now:

apt-get install python

Afterwards, we download and install BlockHosts like this:

cd /tmp
wget http://www.aczoom.com/tools/blockhosts/BlockHosts-2.0.5.tar.gz
tar xvfz BlockHosts-2.0.5.tar.gz
cd BlockHosts-2.0.5
python setup.py install --force

Now we have to edit /etc/blockhosts.cfg. Modify it as follows:

vi /etc/blockhosts.cfg
[...]
HOSTS_BLOCKFILE = "/etc/hosts.allow"
[...]
HOST_BLOCKLINE = ["ALL: ", " : deny"]
[...]
LOGFILES = [ "/var/log/auth.log", "/var/log/proftpd/proftpd.log", ]
[...]
COUNT_THRESHOLD = 3
[...]
AGE_THRESHOLD = 12
[...]
MAIL = True
[...]
NOTIFY_ADDRESS = '[email protected]'
[...]
SMTP_SERVER = "localhost"
SENDER_ADDRESS = 'BlockHosts <[email protected]>'
[...]
IPBLOCK = "iptables"
[...]

In HOSTS_BLOCKFILE we can specify either /etc/hosts.allow or /etc/hosts.deny. It doesn't matter which one we choose. I'm using /etc/hosts.allow here. In the LOGFILES line we specify the log files that BlockHosts should look at. OpenSSH is logging failed login attempts to /var/log/auth.log, ProFTPd to /var/log/proftpd/proftpd.log. COUNT_THRESHOLD specifies the number of failed login attempts from the same host after which BlockHosts should block that host. AGE_THRESHOLD is the numer of hours after which blocked hosts get unblocked. IPBLOCK specifies if you'd like to block hosts with iptables or iproute in addition to adding these hosts to /etc/hosts.allow (or /etc/hosts.deny).

Next we must modify /etc/hosts.allow. First back up your current /etc/hosts.allow:

cp /etc/hosts.allow /etc/hosts.allow_orig

Then empty /etc/hosts.allow and put something like this into it:

cat /dev/null > /etc/hosts.allow
vi /etc/hosts.allow
#
# hosts.allow    This file describes the names of the hosts which are
#        allowed to use the local INET services, as decided
#        by the '/usr/sbin/tcpd' server.
#
# ----
# see "man 5 hosts_access" for details of the format of IP addresses,
#services, allow/deny options. Also see "man hosts_options"
#
# permanent whitelist addresses - this should always be allowed access

ALL: 127.0.0.1 : allow
# ALL: 192.168.0. : allow

# permanent blacklist addresses - this should always be denied access
# ALL: 10. : deny
# ----------------------------------------
# next section is the blockhosts section - it will add/delete entries in
# between the two marker lines (#---- BlockHosts Additions)

#---- BlockHosts Additions
#---- BlockHosts Additions

# ----------------------------------------
# finally, the command to execute the blockhosts script, based on
# connection to particular service or services:

sshd: ALL: spawn /usr/bin/blockhosts.py --verbose --mail --iptables \
     --echo "%c-%s" --check-ip "%h" >> /var/log/blockhosts.log 2>&1 & \
: allow

#---
# add --iproute to enable null-routing, or add --iptables to enable packet
# filtering, which blocks all network communication from blocked hosts
#---
# remove   >> /var/log/blockhosts.log 2>&1     if no logging to blockhosts.log
# is needed - without this, it will still log to syslog (minimally)
#sshd: ALL: spawn /usr/bin/blockhosts.py --verbose --echo "%c-%s" & : allow
#---
# above commands will use default config file - /etc/blockhosts.cfg, edit
# it as needed to specify local configuration options

# See "man hosts.allow" for info on %c and %s identifiers

# for non-verbose, with identification, to syslog only (/var/log/messages),
# triggered on any service (using ALL as first word):
#ALL: ALL: spawn /usr/bin/blockhosts.py --echo "%c-%s" & : allow
#----
# To test hosts.allow, and to find out exact names of SSH/FTP services,
# add this line to the beginning of hosts.allow, use ssh/ftp to connect
# to your server, and then look at the log (/var/log/messages or
# blockhosts.log) to see the name of the invoked service.
# IMPORTANT: after your test is done, remove this line from hosts.allow!
# Otherwise everyone will always have access.
#ALL : ALL: spawn (/usr/bin/blockhosts.py --verbose --echo "%c-%s" >> /var/log/blockhosts.log 2>&1 )& : allow

# -------------------------------------------------------------------------

In the first section you put hosts that you want to whitelist (e.g. 127.0.0.1). If you'd like to whitelist the whole 192.168.0 subnet, uncomment that line.

Then we must add these markers - BlockHosts will add blocked hosts between them:

#---- BlockHosts Additions 
#---- BlockHosts Additions

The most important part is this one:

sshd: ALL: spawn /usr/bin/blockhosts.py --verbose --mail --iptables \
     --echo "%c-%s" --check-ip "%h" >> /var/log/blockhosts.log 2>&1 & \
: allow

Now whenever someone tries to log in using SSH, /usr/bin/blockhosts.py is started, checks the log files that we specified in /etc/blockhosts.cfg, and blocks all hosts with more than COUNT_THRESHOLD failed login attempts by adding them to /etc/hosts.allow and by using iptables (which will totally block these hosts from accessing your system). All actions will be logged to /var/log/blockhosts.log.

Now we need to initialize BlockHosts. First, we do this with the --dry-run option to see if there are no errors:

blockhosts.py --dry-run --verbose

The output could look like this:

server2:/var/log# blockhosts.py --dry-run --verbose
blockhosts 2.0.5 started: 2007-09-05 16:31:10 CEST
... load blockfile: /etc/hosts.allow
... found both markers, count of hosts being watched: 0
no logoffsets found, will read from beginning in logfile: /var/log/auth.log
... loading log file, offset: /var/log/auth.log 0
no logoffsets found, will read from beginning in logfile: /var/log/proftpd/proftpd.log
... loading log file, offset: /var/log/proftpd/proftpd.log 0
... will discard all host entries older than 2007-09-05 04:31:10 CEST
... updates: counts: hosts to block: 0; hosts being watched: 0
#---- BlockHosts Additions
#bh: logfile: /var/log/auth.log
#bh: offset: 2643
#bh: first line:Jun 28 20:35:51 server2 login[2087]: (pam_unix) session opened for user root by (uid=0)
#bh: logfile: /var/log/proftpd/proftpd.log
#bh: offset: 1308
#bh: first line:Sep 05 16:04:34 server2.example.com proftpd[2355] server2.example.com: error setting IPV6_V6ONLY: Protocol not available
#---- BlockHosts Additions
# ----------------------------------------
# finally, the command to execute the blockhosts script, based on
# connection to particular service or services:
sshd, proftpd, vsftpd: ALL: spawn /usr/bin/blockhosts.py --verbose --mail \
--echo "%c-%s" --check-ip "%h" >> /var/log/blockhosts.log 2>&1 & \
: allow
#---
# add --iproute to enable null-routing, or add --iptables to enable packet
# filtering, which blocks all network communication from blocked hosts
#---
# remove >> /var/log/blockhosts.log 2>&1 if no logging to blockhosts.log
# is needed - without this, it will still log to syslog (minimally)
#sshd: ALL: spawn /usr/bin/blockhosts.py --verbose --echo "%c-%s" & : allow
#---
# above commands will use default config file - /etc/blockhosts.cfg, edit
# it as needed to specify local configuration options
# See "man hosts.allow" for info on %c and %s identifiers
# for non-verbose, with identification, to syslog only (/var/log/messages),
# triggered on any service (using ALL as first word):
#ALL: ALL: spawn /usr/bin/blockhosts.py --echo "%c-%s" & : allow
#----
# To test hosts.allow, and to find out exact names of SSH/FTP services,
# add this line to the beginning of hosts.allow, use ssh/ftp to connect
# to your server, and then look at the log (/var/log/messages or
# blockhosts.log) to see the name of the invoked service.
# IMPORTANT: after your test is done, remove this line from hosts.allow!
# Otherwise everyone will always have access.
#ALL : ALL: spawn (/usr/bin/blockhosts.py --verbose --echo "%c-%s" >> /var/log/blockhosts.log 2>&1 )& : allow
# -------------------------------------------------------------------------
Commands (tentative) to run for ip null-route blocking:
... no email to send.
server2:/var/log#

Looks ok (apart from the IPv6 error which you can ignore), so we can run it without the --dry-run option:

blockhosts.py --verbose

This should look like this:

server2:/var/log# blockhosts.py --verbose
blockhosts 2.0.5 started: 2007-09-05 16:33:24 CEST
... load blockfile: /etc/hosts.allow
... found both markers, count of hosts being watched: 0
... loading log file, offset: /var/log/auth.log 2643
... loading log file, offset: /var/log/proftpd/proftpd.log 1308
... will discard all host entries older than 2007-09-05 04:33:24 CEST
... updates: counts: hosts to block: 0; hosts being watched: 0
... created user-defined chain blockhosts
... creating jump from INPUT to blockhosts chain
... no email to send.
server2:/var/log#

BlockHosts is now ready to check for failed SSH logins, but not for failed ProFTPd logins because Debian's ProFTPd doesn't check /etc/hosts.allow and /etc/hosts.deny, which means BlockHosts isn't invoked when someone tries to log in to ProFTPd (of course, if someone has COUNT_THRESHOLD or more failed log in attempts on ProFTPD and then tries to log in to OpenSSH, he will be blocked, because OpenSSH uses /etc/hosts.allow which then invokes BlockHosts which finds the failed login attempts to ProFTPd; but if someone tries to log in to ProFTPd only, there's no way to catch him with the current setup). To block non-TCP_WRAPPERS services, we will create a cron job that starts BlockHosts every five minutes (for example).

Share this page:

0 Comment(s)