Comments on Preventing SSH Dictionary Attacks With DenyHosts
Preventing SSH Dictionary Attacks With DenyHosts In this HowTo I will show how to install and configure DenyHosts. DenyHosts is a tool that observes login attempts to SSH, and if it finds failed login attempts again and again from the same IP address, DenyHosts blocks further login attempts from that IP address by putting it into /etc/hosts.deny. DenyHosts can be run by cron or as a daemon. In this tutorial I will run DenyHosts as a daemon.
43 Comment(s)
Comments
Denyhosts is alredy packaged for debian distribution and it run out of the box. Officially is part of SID branch, and unofficially, I'm maintaing last version in my repository:
http://bertorello.ns0.it/debian/binary/denyhosts/
Note: init script in debian package are full LSB-compilant. The one in author's tarball is a python script.
I've tried the Debian Package on Debian Sarge. First, you must have the package lsb-base installed, because the init script needs it, and furthermore the init script needs the function log_daemon_msg which isn't included in the lsb funtions. Therefore the init script fails. You can make it work by creating the function log_daemon_msg yourself, but it's not the clean way.
If you could adjust your Debian packages so that they work on Debian Sarge it would be great! :-)
There is little use (IMHO) to complain about sid packages that do not work on sarge. You cannot expect the packager to handle those too, as Sarge has been released already so no new packages will go into it.
I used the .deb package on Ubuntu 5.10 and ran into the same problem with log_daemon_msg. For me the easy way out was changing the init-script's use of this function to log_success_msg which is in the lsb.
Thanks for the heads up on this people, however the site listed above (for debian package) isn't working..
Easy enough to build and install though...
pam_abl is a PAM component that auto blacklists hosts responsible for repeated failed login attempts. http://hexten.net/pam_abl
I was just wondering if there wasn't such a PAM module... looks to me that PAM is the aproach that makes more sense.
Nice one - this helps a lot.
I have automated the install of DenyHost on Ubuntu. Get the script here: http://www.hildoersystems.com/index.php/tutorials/security/36-security-tutorials/60-automated-install-of-deny-host-ssh-security-for-ubuntu
Falko,
The --purge command is only necessary when running from the command line. If you run DenyHosts as a daemon and set your PURGE_INTERVAL, then DenyHosts will automatically purge the expired entries that are older than PURGE_DENY every PURGE_INTERVAL. That is, if PURGE_DENY = 5d (5 days) and PURGE_INTERVAL = 1h (1 hour) then each hour DenyHosts will remove any /etc/hosts.deny entries that are older than 5 days.
Other than that, great article!
Readers may also be interested in the new synchronization mode too. For more information: http://www.denyhosts.net/faq.html#sync
Phil Schwartz
(you might also remember me from such projects as DenyHosts)
Hi, I discovered the DenyHostscript sometime ago. I think it was through /. It has now been running for a few months on my server and manages in general to repel around two attacks a day.
# apt-get install fail2ban
One of the benefits of running Debian Sarge is the ability to run servers without too much change, and also the ability to apt-get packages. This allows one to run servers and other services without worrying about and manually tracking security updates. Simply cronning apt-get update/upgrade nightly, plus manually checking for packages that fail --assume-yes (trivial) regularly allows one to keep a system up to date for patches and for security issues.
One issue when Sarge was still in testing was when KDE went through a major upgrade. kdm/gdm then required a large number of manual changes to retain the changes made to the original kdm/gdm when previously installed.
There are two concerns with this example and not using non-deb packages. The first is the changes that would need to be made to the config file after an update/upgrade to the next version. The second concern is, wouldn't the config file be overwritten, or wouldn't manual intervention be needed due to the config file being located outside of /etc? This is especially a concern when dealing with packages that have to do with the security of the system. What if I forget that the package has a config file outside of /etc, update/upgrade it or install the latest tarball, then am left with an overwritten config file? Or realize what happened, but didn't schedule time to re-configure the config file?
While the alternative is easy to understand, no package (for Sarge) if relying on a deb file due to the issues brought up in the comments, or package/functionality available if using the tarball, as a non-guru, I'm relying on these great how-to's to kickstart my venture into other services. As I believe quite a few others are. Wouldn't it be a good idea to give a heads up about the possibility of overwriting a config file during an upgrade of the package?
Great how-to anyway. As are the others. Keep them coming!
Another approach that is more generic (can be used with any port/service) is to use the IPT_RECENT module that comes with netfilter:
For example I have the following lines in my iptables config:
iptables -N SSH_CHECK
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j SSH_CHECK
iptables -A SSH_CHECK -m state --state NEW -m recent --set --name SSH
iptables -A SSH_CHECK -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH
iptables -A SSH_CHECK -m state --state NEW -m recent --rcheck --seconds 60 --hitcount 4 --name SSH -j DROP
which basically kick-bans the source IP for 60 seconds if more than 3 connections are attempted in a 60 second limit.
I've found this to be 100% effective.
This will watch and if there are more than 3 ssh connections within a 60
second span, new ssh connections will be rate limited. Existing connections
are unaffected, and anything in your white list is unaffected. You can still
make new SSH connections, though it takes a lot longer for the session to come
up.
iptables -N ALLOWED
# accept already establed and related connections
iptables -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# don't rate limit ssh from the following
iptables -A INPUT -s $WHITE_LIST_IP_ADDRESS -p tcp -m tcp --dport 22 -j ACCEPT
# rate limit on excessive ssh connections
iptables -A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ALLOWED
# rate limiting
iptables -A ALLOWED -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A ALLOWED -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -m limit --limit 3/min --limit-burst 3 -j ACCEPT
iptables -A ALLOWED -p tcp -j LOG --log-tcp-options --log-ip-options --log-prefix " DROP RATE_LIMIT "
iptables -A ALLOWED -p tcp -j REJECT --reject-with icmp-port-unreachable
Obviously you would need to integrate this into your existing iptables config.
I personally use iptables-save / iptables-restore to keep and edit my
configuration.
And this iptables solution is far much better than anything else I've found yet. I can't predict who and from where the attack is. It could be a windows machine on a dial-up. So permanent blacklisting isn't an option. iptables allows me to block them temporarily and that's much better. :-)
I have successfully used "Another approach" on several of my systems. But i have one 4-processor AMD system running a 64-bit kernel.
Apparently, on that specific system with kernels around 2.6.8 (say a Debian stock kernel) or so, this recipe causes a crash after about 25 days.
It may be fixed around 2.6.12, so with a newer kernel you'd probably be in ok shape.
i like the iptables solution pretty well (it's stock), but would like to log failed attempts... any suggestions please post here and also email to [email protected]
thanks!
pau1
before the drop line you could do this: iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH -j LOG --log-prefix "SSH Flood: " --log-level info -xaeth
Pau1,
If you want log and view failed attempts, install Logcheck. I use it under Debian stable and it will email you every couple hours of any major changes in your system or failed access attempts to your machine. All I did to fix the ssh hacker attempts was to change the port number that ssh listens on. Now I really don't have a hacker attempt problem. Hope this helps.
Hello,
I'm also using the recent match in iptables, and according to me , your setup can be simplified :
iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH
in stead of the last two in your example.
I've left out the -m state --state NEW because it's allway true, and
the rule with the --update option can be left out, by just replacing the --rcheck in the last rule by --update.
It becomes then:
iptables -N SSH_CHECK
# here come checks for integrity, portscans(psd) etc
# here allow related traffic
iptables -A INPUT -p tcp --dport 22 -m state NEW -j SSH_CHECK
iptables -A SSH_CHECK -m recent --set --name SSH
iptables -A SSH_CHECK -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP
Stef
make that
... -m state --state NEW ...
I found this post very helpful to get me started with Linux firewalls. I'm just a bit surprised that nobody mentions ip6tables - as I understand it that door will remain wide wide open! And of course ip6tables does not support "recent" so we better unconditionally drop there.
Dirk
Personally i think the iptables way is the most optimal way to go, even you understand the OSI layers you will agree with me, with iptables the packet will be dropped at layer 4, but with denyhosts it will traverse the path up to layer 7 before a decision can be made.
Why is your system open to everyone? Wouldn't "default deny" and granting
access to people who should be using it be a much safer alternative?
Even allowing only a few users to get access does not prevent Dictionary attacks on the accounts. If you host a shell server for example, all users need SSH access and DenyHosts is a good system to prevent dictionary attacks.
If you want to try an alternative method of blocking dictionary attacks on SSH, try sshdfilter: http://www.csc.liv.ac.uk/~greg/sshdfilter/ It runs as a daemon, like Denyhosts. It executes SSHD itself, and so blocks can be initiated instantly (the program is constantly monitoring your sshd log). It also logs all attempts, and a supplied Logwatch script can give you periodical summaries.
Been using sshdfilter for quite a while on one of my server and i can say i love it. I had trouble in 2004 with some dict. attacks, but in 2006 i tried sshd and it worked quite well. I heard DenyHost is pretty good too, haven't tried it yet though. The recipe for success might be to get ready before the attacks instead of patching after :)
Patt's Frostings!
First of all, thanks for the great write-up. denyhosts immediately blocked 14 hosts upon startup!
Secondly, for redhat/fedora, you can subsitute the following command in the tutorial:
update-rc.d denyhosts defaults
with the following:
chkconfig denyhosts --add
to accomplish the same end. -tm
If python complains about a missing Makefile when you run "python setup.py install", you might be missing the python-dev package -- I was. "apt-get install python-dev" and I was good to go.
1. AllowGroup - in sshd_config will allow only users in specific groups. Our servers have alot more users than just those who need ssh access.
2. A little ugly perl script which will email a netblock admin where the attack came from ONCE PER ATTEMPT that a host on their network has been compromised:
http://www.neuropunks.org/~max/parse_ssh.pl
This is really only usefull on FreeBSD machines which email root a security summary for the day. In our case, it is called from procmail to parse that message.
Heres a recipe:
:0c
* ^Subject:.*security*
| /root/system/bin/parse_ssh.pl
Well, this might be of intrest to all off you, i thougt to share it here ...
From the website: http://denyhosts.sourceforge.net/
Denyhosts v2.3 contains a security fix
(purged hosts were not always re-added when they should have been). If you are using an earlier version it is strongly recommended that you upgrade to v2.3 or later
PS the latest version is 2.4b April 9, 2006
Gr Ovis
First, I want to thank Falko Timme for the helpful article on setting up DenyHosts
for Debian. It was very clear and easy to follow. I got DenyHosts running in
no time.
After I got it working, I couldn't help but move things around to make it
more "standards-compliant". I didn't want to use the .deb package because it's still in testing and i'm using stable. So Here's how i went about it:
mkdir /var/lib/denyhosts
chown root:root /var/lib/denyhosts
chmod 750 /var/lib/denyhosts
Then modified /usr/share/denyhosts.cfg to include:
WORK_DIR = /var/lib/denyhosts
Run it once (to create the files inside $WORK_DIR) then:
chmod o-rwx -R /var/lib/denyhosts
mkdir /etc/denyhosts
chown root:root /etc/denyhosts
chmod 750 /etc/denyhosts
mv /usr/share/denyhosts/daemon-control /etc/denyhosts/
mv /usr/share/denyhosts/denyhosts.cfg /etc/denyhosts/
chmod o-rwx -R /etc/denyhosts
Also:
rm /etc/init.d/denyhosts
ln -s /etc/denyhosts/daemon-control /etc/init.d/denyhosts
and modify /etc/denyhosts/daemon-control to include:
DENYHOSTS_CFG = "/etc/denyhosts/denyhosts.cfg"
And finally:
chmod o-rwx -R /usr/share/denyhosts
chmod o-rwx /usr/bin/denyhosts.py
PS.
As I wanted to always run it with the --purge option i simply edited
/etc/denyhosts/daemon-control to include:
DENYHOSTS_BIN = "/usr/bin/denyhosts.py --purge"
et voila
I have automated the install of DenyHost. Get the script here: http://www.hildoersystems.com/index.php/tutorials/security/36-security-tutorials/60-automated-install-of-deny-host-ssh-security-for-ubuntu
Hello,Please someone should please teach me how to find smtp using putty and also give me every code needed to get the smtp,here is my email,i will appreciate your prompt response,please send me every details on how to get smtp to [email protected].
Hi Falko,
It's really helpful guide.
Thanks and Regards,
Ganesh Waghumbare.
Falko, Your "how to" still works great for setting up DenyHosts-2.6 on Ubuntu Server 9.04 http://sourceforge.net/projects/denyhosts/files/denyhosts/2.6/DenyHosts-2.6.tar.gz/download There is ONE "path correction" however, in the daemon-control file change; DENYHOSTS_BIN = "/usr/bin/denyhosts.py" to DENYHOSTS_BIN = "/usr/local/bin/denyhosts.py" Thanks for your expertise....
wow i was stoked to find this .... then i installed it and found out that i had to go back to college to learn how to get it configured with all these config files ..... there isn't a reason in the world that you couldnt have included the config files in the install ................ this right here is why linux will NEVER be a reasonable desktop replacement os .... less then 1% of computer users will spend 5 years studying to learn the code required to run a linux system the rest will rely on point and click uninstalling now to look for a security utility that wont take me a month to figure out
oneyearuser you should use a newer howto on denyhosts since it already seems to be included in repositories (with configfiles included in the install)
on the other hand, why would you even need denyhosts on a desktop-machine? where you assumably don't have a ssh-server installed.
Note that the above post is four years old. On my Debian system the config is in /etc/ and I think was setup automatically.
Jamie
I see my hosts.deny file has grown to about 10000 entries after 12 months,
Is there a max file size for hosts.deny?
If over a few years it grows to many 10000's does this affect performance to the server eventually?
I currently have set PURGE_DENY =
Should I change it to something like PURGE_DENY = 360d ?????
Any thoughts appreciated
This is perfect for blocking all those china hacking attempts! Thanks for the How-To and thanks to the Denyhosts developer!
Great article Falko.
I know this article was written 6 years ago, but just thought I'd give you heads-up the download URL provided isn't working anymore.
This worked for me: wget "http://downloads.sourceforge.net/project/denyhosts/denyhosts/2.6/DenyHosts-2.6.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fdenyhosts%2Ffiles%2F&ts=1339534547&use_mirror=voxel" -O DenyHosts-2.6.tar.gz
Great tutorial! Thanks!
DENYHOSTS_BIN = "/usr/bin/denyhosts.py"
should be
DENYHOSTS_BIN = "/usr/local/bin/denyhosts.py"