Brute Force Protection with BlockHosts
Posted by chr0nik on Mon 30 Jan 2006 at 14:02
Brute force attacks are a weekly issue on my Debian box and until now, I've manually managed my hosts.allow and hosts.deny files. The issue isn't so much the actual security threat as brute force attacks are usually unsuccessful, but seeing log files that are just loaded up with thousands of failed login attempts is unnerving at best.
I've searched for solutions from the black list daemon (bld) that's available as a Debian package to more complicated iptables based protection. I haven't really found whether any other services actually use bld and as far as iptables, I have a great firewall script already that I don't want to tinker with anymore.
The Solution:Enter BlockHosts; a python script that even a novice can setup, unless the existing log file patterns do not meet your needs... then you'll need a regex guru.
BlockHosts v1.0.3 has built-in support for OpenSSH, ProFTPD and vsftpd. By built-in support, I mean that blockhosts.cfg already contains regular expressions to match failed login attempts for those services. Because of the fact that the installation is so trivial and well documented in the text files included in the BlockHosts distribution, I will only cover the steps at a high-level.
Installation:BlockHosts needs Python 2.3. It will also need the development package as it will look for the Python Makefile when you run BlockHosts' setup script. These packages are installed easily with apt-get:
apt-get install python2.3 python2.3-dev
Additionally, you'll need to ensure that the services you wish to protect are being invoked by inetd and not running in standalone mode. You will also need to ensure you're using tcp_wrappers. My /etc/inetd.conf looks like this:
ftp stream tcp nowait root /usr/sbin/tcpd /usr/sbin/vsftpd ssh stream tcp nowait root /usr/sbin/tcpd /usr/sbin/sshd -i
Once you've downloaded and unpacked the GZIPped tarball from the download page, the installation is fired off by executing this command:
python setup.py install --force
This copies the main script, blockhosts.py, to /usr/bin and places the configuration file, blockhosts.cfg in /etc. There is really only one thing you have to be concerned with in /etc/blockhosts.cfg and that's the line that specifies where your system log files are. Again, there are examples and abundant comments in the config file so you shouldn't have any difficulty maintaining it. Mine looks like this:
LOGFILES = [ "/var/log/auth.log", "/var/log/vsftpd.log", ]
Finally, modifications are required to your /etc/hosts.allow file. The overall format of hosts.allow is defined as:
- Manually maintained whitelist
- BlockHosts marker lines
- The command to fire off BlockHosts on inbound connection attempts
My /etc/hosts.allow file now looks like this:
# permanent whitelist addresses - these should always be allowed access ALL: 127.0.0.1 : allow ALL: 192.168.1. : allow # permanent blacklist addresses - these should always be denied access ALL: 10. : deny ALL: 192. : deny ALL: 172. : 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, for example, here's what # I use: sshd, vsftpd, in.vsftpd: ALL: spawn (/usr/bin/blockhosts.py --verbose --echo "%c-%s" >> /var/log/blockhosts.log 2>&1 )& : allowConclusion:
BlockHosts will now evaluate my log files on each connection attempt, maintain a "watched" host list between the markers in /etc/hosts.allow, and maintain the current blocked hosts in /etc/hosts.deny. The default configuration is to block a host after 7 failed login attempts and to reset the block list after 12 hours (+/- some tolerance based on the timing of log file writes, etc.)
BlockHosts is easy to install and quite effective. If nothing else, I know I'll sleep better knowing that now after 7 failed logins instead of thousands of failed logins, the attacker will be dissuaded.
Simple, effective, no configuration needed.
See also:
Keeping SSH access secure http://www.debian-administration.org/articles/87
[ Parent | Reply to this comment ]
Seconded, if only because I don't want to start SSH via inetd.
[ Parent | Reply to this comment ]
http://packages.debian.org/unstable/net/fail2ban
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
fail2ban installs and runs perfectly in sarge. Install with dpkg -i, or if you have other packages from sid or from backports.org as I do, just use /etc/apt/preferences to automatically manage package selections.
$ man apt_preferences
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
I'm using denyhosts, which is also a python script very similar to blockhosts. I don't know about blockhosts, but denyhosts can be configured to write the blocked hosts in a separate file, e.g. /etc/hosts.blocked, which you can then include from /etc/hosts.deny. This has the advantage of keeping hosts.deny free from hundreds of IP addresses.
http://denyhosts.sourceforge.net/
[ Parent | Reply to this comment ]
Thanks to the author of BlockHosts, Avinash Chopde, for the correction.
[ Parent | Reply to this comment ]
The simplest is that depending upon your network config, an attacker can spoof the failed connections to cause you to block access to arbitrary hosts, controlling your network connection as a denial of service or as a prelude to other mischief. Ensuring that these failures represent unspoofed connections is a matter of configuring your services and network stack. Keep on top of these issues.
A more worrying problem is that the regexes as shipped in these packages are often very poorly analyzed (as regexes typically are!) enabling people to login with names like 192.168.0.4, causing that IP address to be blocked. Some of these methods are service specific, but the regexes are often loose enough to be fooled. This definitely affected fail2ban, and I expect it to recur with sufficient creativity and/or laziness over time.
There is also the general problem, which does not affect most stock-configured debian services, of DNS problems. That is, if a service logs reversed hostnames, rather than IP addresses, can be manipulated by causing forward resolution of the name to map to an arbitrary IP address, again allowing the attacker to cause your system to block access to an arbitrary IP address. To safely employ this type of system, your services must log IP addresses, not hostnames.
[ Parent | Reply to this comment ]
A more worrying problem is that the regexes as shipped in these packages are often very poorly analyzed (as regexes typically are!) enabling people to login with names like 192.168.0.4, causing that IP address to be blocked.Are you refering to a very old fixed bug? :-) I think I have fixed that bug by providing a regext for the full log line, thus it is impossible to perform DoS via providing fake IPs in the user names
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
http://denyhosts.sourceforge.net/
And I've made a debian package:
http://denyhosts.sourceforge.net/faq.html#1_12
available by adding this repository:
deb http://bertorello.ns0.it/debian binary/
P.S.
This packages will be available in official SID repository as soon as possible
[ Parent | Reply to this comment ]
-A CHAINNAME -i <interface> -p tcp -m tcp --dport 22 -m state --state NEW -m recent \
--set --name DEFAULT --rsource
-A CHAINNAME -i <interface> -p tcp -m tcp --dport 22 -m state --state NEW -m recent \
--update --seconds 60 --hitcount 4 --name DEFAULT --rsource -j DROP
Rate limits connections to 4 per minute per IP. Anything more is dropped. You can choose to tarpit/log/redirect hostile hosts but leave your service open. Needs no intervention or maintenance. Works for me...
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
/sbin/route add -host $TARGET_IP$ gw 333.444.555.666
This will block all traffic going to TARGET_IP. It's nice to find a tool to block brute force SSH attacks. I don't really like the idea of perminantly banning the IPs though, since they are usually dynamic addresses. I go in once a week or so and clean up my routing table.
[ Parent | Reply to this comment ]
http://packages.debian.org/unstable/net/fail2ban
[ Parent | Reply to this comment ]
you mention how easy the installation is...
after reading this line
python setup.py install --force
I wondered, why --force? what problems are we working around?
aaron
Through correctness comes ease
-Chiun
-The Destroyer series
[ Parent | Reply to this comment ]
David
[ Parent | Reply to this comment ]
apt-get install denyhosts
[ Parent | Reply to this comment ]
There is also denyhosts already packaged : apt-get install denyhostsdenyhosts is not yet in the sarge repositorys.
[ Parent | Reply to this comment ]
SSHD_FORMAT_REGEX = .*? (?P<message>.*)
FAILED_ENTRY_REGEX = .*FAIL LOGIN.*(Client "(?P<host>\d*\.\d*\.\d*\.\d*)*)"
SUCCESSFUL_ENTRY_REGEX = .*OK LOGIN.*(Client "(?P<host>\d*\.\d*\.\d*\.\d*)*)"
:) bort_83
[ Parent | Reply to this comment ]
Other than that, thanks for the nice description.
[ Parent | Reply to this comment ]