Google the SiteQuicksearchCategoriesSyndicate This BlogCreative CommonsBlog Administration |
Saturday, December 30. 2006Block Brute Force Attacks Against sshd and proftpd Using blockhosts
For a long time now I've had a lot of problems with brute force attacks against sshd and proftpd - attacks where a host will attempt to login with a dictionary of common usernames and passwords, trying each one until they find a combination that works. Apart from being a security issue, this uses up a lot of bandwidth so it's worth taking some measures to block these kind of attacks.
Both sshd and ftpd services have their own individual means for blocking individual connections, but unfortunately neither have an inbuilt method for detecting brute force attacks - counting how many failed login attempts are made from each individual IP address and then blocking that IP address if the number of failed login attempts is more than a certain number. This is where a 3rd party utility is required. There are a few utilities that can mitigate brute force attacks on services. For a while now I've used DenyHosts successfully to block sshd brute force attacks. DenyHosts works by constantly monitoring sshd logfiles and keeping track of how many failed logins have occured per IP address over time. If the number of failed logins reaches a certain threshold, DenyHosts adds an entry in /etc/hosts.allow that effectively blocks the IP address, stopping that host from connecting to the sshd service any more. DenyHosts is great, but unfortunately it's aimed only at blocking sshd brute force attacks and I need to protect the ftpd service as well as just sshd - and in future maybe adapt to block other services. With this in mind I decided to move to using a very similar script called BlockHosts (the documentation for BlockHosts actually mentions that it was inspired by DenyHosts). BlockHosts can scan a list of service logfiles in one go instead of just a single logfile as with DenyHosts, so is ideal for monitoring a number of different services for brute force attacks. The following describes how to install and configure BlockHosts on FreeBSD so it's executed every time the sshd or proftpd services are accessed using TCP_WRAPPERS - ie modifying /etc/hosts.allow so the blockhosts script is run each time sshd or proftpd are accessed. The BlockHosts script will then check if this current connection attempt is part of a brute force attack and if so, add a blocking rule to /etc/hosts.allow to deny further access. Installation of BlockHosts
We're now ready to run blockhosts.py for the first time. BlockHosts will parse each logfile mentioned in blockhosts.cfg and check for any brute force attacks and if it finds any, blocks will be added to the /etc/hosts.allow file. Note: This initial check does not take into account the period over which failed logins took place, so any IP that has more than the default 7 failed login entries will look like a brute force attacker. However, the ban BlockHosts adds will only last for the default 12 hours so this shouldn't cause a huge issue - just be aware of this and check the IPs that are added on the first run. For the very first time it's a good idea to try a 'dry run' just to see what blockhosts finds and what it'd do, without actually doing anything to the /etc/hosts.allow file. To do this, run blockhosts with the '--dry-run' flag: CODE: root@users /usr/local/etc# /usr/local/bin/blockhosts.py --verbose --dry-run blockhosts 1.0.5 started: 2006-12-30 14:15:30 ... will discard all host entries older than 2006-12-30 02:15 ... load blockfile: /etc/hosts.allow ... found both markers, count of hosts being watched: 0 Warning: no offset found, will read from beginning in logfile: /var/log/auth.log ... securelog, loading file, offset: /var/log/auth.log 0 Warning: no offset found, will read from beginning in logfile: /var/log/ftp.log ... securelog, loading file, offset: /var/log/ftp.log 0 ... updates: counts: hosts to block: 9; hosts being watched: 21 #---- BlockHosts Additions ALL: 203.88.192.225 : deny ALL: 200.71.192.7 : deny ALL: 212.227.81.146 : deny ALL: 218.25.62.75 : deny ALL: 200.46.108.164 : deny ALL: 201.57.163.2 : deny ALL: 205.129.191.11 : deny ALL: 200.68.51.91 : deny ALL: 82.38.68.217 : deny #bh: ip: 85.184.10.200 : 1 : 2006-12-30-14-15 #bh: ip: 84.158.231.209 : 1 : 2006-12-30-14-15 #bh: ip: 82.38.68.217 : 11 : 2006-12-30-14-15 #bh: ip: 82.153.28.16 : 2 : 2006-12-30-14-15 #bh: ip: 67.113.225.66 : 1 : 2006-12-30-14-15 #bh: ip: 59.108.34.228 : 2 : 2006-12-30-14-15 #bh: ip: 222.68.192.132 : 2 : 2006-12-30-14-15 #bh: ip: 218.25.62.75 : 20 : 2006-12-30-14-15 #bh: ip: 217.83.162.157 : 1 : 2006-12-30-14-15 #bh: ip: 212.227.81.146 : 29499 : 2006-12-30-14-15 #bh: ip: 210.1.132.178 : 4 : 2006-12-30-14-15 #bh: ip: 205.129.191.11 : 20 : 2006-12-30-14-15 #bh: ip: 204.141.87.14 : 3 : 2006-12-30-14-15 #bh: ip: 203.88.192.225 : 448 : 2006-12-30-14-15 #bh: ip: 202.108.40.109 : 1 : 2006-12-30-14-15 #bh: ip: 201.57.163.2 : 2867 : 2006-12-30-14-15 #bh: ip: 200.71.192.7 : 761 : 2006-12-30-14-15 #bh: ip: 200.68.51.91 : 10 : 2006-12-30-14-15 #bh: ip: 200.46.108.164 : 170 : 2006-12-30-14-15 #bh: ip: 200.105.255.90 : 7 : 2006-12-30-14-15 #bh: ip: 152.104.125.14 : 3 : 2006-12-30-14-15 From this you can see nicely what blockhosts makes of the service logfiles and the addresses that have tried to connect unsuccessfully. On my host, as you can see above, there are a few that are obviously dodgy (I would only expect a max of maybe 8 connections per ip per month, so clearly 29,499 connections is just wrong!). Once you're happy that the output is correct, run blockhosts again without the '--dry-run' flag and the /etc/hosts.allow file will be modified. Also from now on the logfiles will only be read from the last recorded offset which saves a lot of time if your logfiles are very big. Big thanks to the BlockHosts author Avinash Chopde ! Saturday, November 18. 2006Let root see all files with locate
The locate utility on linux was one of the first tools I hit when I made the move to FreeBSD a few years back - knowing where files are is half the battle when you're trying to configure things and find documentation on how to do it. The trouble with locate though as jdarnold mentions in his article 'Locate This!' is that if you build the locate database as 'root', you end up exposing everything to any user that runs the locate command. The other problem he mentions is the locate db is only updated weekly on FreeBSD by default via the periodic system which isn't really enough if you use your system regularly.
I remember thinking along the same lines a while back and after reading through the man pages the solution I found was to create two separate databases - one for root and one for regular users. The 'regular' db is updated on a weekly basis as per the default on FreeBSD via periodic, whereas the other 'root' locate db is built daily in a crontab so I can get the latest up to date details on which files are where. To get the root db built first you need to create a crontab entry - i put this in /etc/crontab: CODE: 39 2 * * * root env -i LOCATE_CONFIG=/root/locate/conf/locate.rc /usr/libexec/locate.updatedb > /dev/null 2>&1 This tells the locate.updatedb script to use a separate configuration file - /root/locate/conf/locate.rc - for building root's locate db. The content of /root/locate/conf/locate.rc look like this: CODE: FCODES="/root/locate/db/locate.database.root" which indicates that this db should be built in /root/locate/db/locate.database.root instead of the default locate in /var/db/locate.database. You can safely run the command as root on the commandline to initialize your new db: CODE: root@users /root# env -i LOCATE_CONFIG=/root/locate/conf/locate.rc /usr/libexec/locate.updatedb Once the database is built you can move on to test the new db works ok: CODE: root@users /root# locate -d /root/locate/db/locate.database.root .cshrc.root /root/.cshrc.root This file is only readable by root, so it seems to work ok. To make things easier, add a shell alias in root's .cshrc file aliasing 'locate' to the command 'locate -d /root/locate/db/locate.database.root': CODE: root@users /root# grep locate $cshrc alias locate locate -d /root/locate/db/locate.database.root With the "-d /root/locate/db/locate.database.root" switch, locate will use the db at /root/locate/db/locate.database.root instead of the default /var/db/locate.database and root will be able to use locate to find any files in the filesystem, not just those that are world readable. Finally, one way to update the regular locate db as root but without making it list every world readable file is to perform the following: CODE: #!/bin/sh # make sure db file exists: touch /var/db/locate.database # then change ownership to the nobody user: chown nobody /var/db/locate.database # make it writeable by nobody and readable by everyone else: chmod 644 /var/db/locate.database # then move on to update the db... # first make sure we're in the / folder where the db update starts: cd / # then finally run the updatedb command as the 'nobody' user: echo "/usr/libexec/locate.updatedb" | su - -fm nobody This is basically what the 310.locate periodic script does and results in a locate db that contains only files that are readable by the 'nobody' user - essentially all 'world readable' files. Comparing the sizes of the root db against the nobody db: CODE: root@users /# ls -al /var/db/locate.database /root/locate/db/locate.database.root -rw-r--r-- 1 root wheel 4070484 Nov 18 02:45 /root/locate/db/locate.database.root -rw-r--r-- 1 nobody wheel 3280409 Nov 18 11:41 /var/db/locate.database You can see the size difference there, not as many entries in nobody's db as root's. Just to double check: CODE: root@users /root# locate .cshrc.root /root/bin/ktrace.out /root/ktrace.out /usr/local/etc/snort/ktrace.out root@users /root# echo "locate ktrace.out" | su - -fm nobody /usr/local/etc/snort/ktrace.out So from that you can see that 'nobody' can see the ktrace.out files located in /root - apart from root of course :) Sorted. Monday, September 4. 2006Solving permission problems with parsepath.pl
parsepath.pl is a brilliant perl script for fixing permissions problems on Unix based platforms by Jeremy Mates. Probably the most common type of permission problem from a sysadmin/webmaster's viewpoint is uploading a file to a directory in a website's document root folder and then trying to access the file or script in a web browser only to get the dreaded 403 error message:
Forbidden Most time the solution is very simple, just change the permissions on 'test.php' to make sure the user the webserver runs as can read the file correctly - the simplest and most common method being to change the mode of the file to '755': CODE: chmod 755 test.php Unfortunately sometimes it's not that easy and many times you see users asking 'I'm getting 'access denied' errors even though I've changed the perms to 755'. The problem is that one of the subdirectories that the 'test.php' file lives in has permissions set so that the webserver can't read the file properly. Now that's where the headache comes in :) However, parsepath.pl can take the headache out of fixing permissions problems. Say you have a website document root directory tree /usr/local/www/web/www.munk.me.uk/foo/bar and you upload a web script 'test.php' into that directory. You try and access the file in a webbrowser but get the 403 permission denied error above. First off you check the permissions on the file itself: CODE: [23:58:17] root@users /usr/local/www/web/www.munk.me.uk/foo/bar# ; ls -l total 0 -rwxr-xr-x 1 www www 0 Sep 4 23:39 test.php That looks ok, with permissions 755 and the owner/group set to 'www' the webserver user 'www' should be able to read the file ok. So in this case the problem must be with the permissions on one of the parent subdirectories. The old method of working out the perms would be either to trawl one by one through each directory checking the perms on each subdirectory or to change the permissions recursively on the document root folder so all subfolders have the read bit set for the webserver user/group. With parsepath.pl things are a lot simpler though - just run the following command: CODE: [0:03:21] root@users /usr/local/www/web/www.munk.me.uk/foo/bar# parsepath.pl user=www +r test.php ! group=www +rx fails: d 0700 root:www /usr/local/www/web/www.munk.me.uk/foo ! unix-other +rx fails: d 0750 root:wheel /usr/local/www/web/www.munk.me.uk/foo/bar With this command parsepath.pl recurses through each subdirectory below the file/path you feed it on the commandline and tells you the permissions problems - if any - for the user 'www' (the user=www argument) to read (the +r argument) the file 'test.php'. In the output, we're told that permissions to read the test.php by the user www fails on two counts: CODE: # the group bit on the folder 'foo' doesn't have the +rx flag set: ! group=www +rx fails: d 0700 root:www /usr/local/www/web/www.munk.me.uk/foo # the other bit on the folder 'bar' doesn't have the +rx flag set: ! unix-other +rx fails: d 0750 root:wheel /usr/local/www/web/www.munk.me.uk/foo/bar With this information it's easy enough to go in and make the changes necessary to fix the problem using 'chmod g+rx foo foo/bar'. There are other ways of invoking parsepath.pl though. Running it just with a file/path as an argument it'll tell you the permissions on each subdirectory under it: CODE: [0:10:33] root@users /usr/local/www/web/www.munk.me.uk/foo/bar# > parsepath.pl /usr/local/www/web/www.munk.me.uk/foo/bar/test.php % /usr/local/www/web/www.munk.me.uk/foo/bar/test.php d 0755 root:wheel / d 0755 root:wheel /usr d 0755 root:wheel /usr/local d 0755 root:wheel /usr/local/www d 0770 www:wheel /usr/local/www/web d 0750 www:www /usr/local/www/web/www.munk.me.uk d 0700 root:www /usr/local/www/web/www.munk.me.uk/foo d 0750 root:wheel /usr/local/www/web/www.munk.me.uk/foo/bar f 0755 root:www /usr/local/www/web/www.munk.me.uk/foo/bar/test.php which can is better to see a whole tree in one go. No permissions were harmed in the making of this article! I'll include the parsepath.pl script in the extended article just in case the original ever gets lost - big credit of course goes to the author of the script, Jeremy Mates. His site is actually very interesting from a sysadmin's point of view containing lots of interesting admin scripts and thoughts on system administration in general - spent quite a while grazing through his stuff there - cheers Jeremy. Continue reading "Solving permission problems with parsepath.pl" Wednesday, August 30. 2006Eliminate SSH Passwords in Putty
I use the SSH client Putty to login to my FreeBSD server from my Windows workstation and entering passwords on the commandline can be a chore. Starting up Putty and connecting to servers you use regularly via SSH can be made a lot easier though by using secure keys, allowing you to fire up putty and get 'auto logged in' without the need for password entry.
The idea is you create a pair of keys on the machine from which you'll be logging in via SSH, one public and one private. The public key is stored on the server to which you're logging into and the private key is stored at the machine you'll be logging in from. Once both keys are in place, you can associate your private key with the SSH session associated with the server where the public key lives at the other end. Now when you login you don't need to enter a password - Putty sends the public key information along at the authentication phase, the remote server checks the private key against the public key it finds on the server and if everything checks out you're logged in without being prompted for a password. There's a great article for setting up a key pair in the PuTTYgen utility and installing the key on the remote server on this site, the basic steps are:
Copy the public key into the file ~/.ssh/authorized_keys (or ~/.ssh/authorized_keys2 for SSH2, though I think SSH2 still reads ~/.ssh/authorized_keys). The public key usually looks similar to this: CODE: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEApiVHreNg3Xnmrl9lo6nCpsb+ iytNHBZDztLshEhLaucQCs66b0K2fjpfl3KheQB9lpIBBtL0NaPZslo1fVGnJT8fF4ZywIyNuKzN8cYM+ zfIMjqe8UxQD1QfE1s4QxBhgyihGb6PwQkYJeWfMaINq5pnuHzx2Fc1kWRMdaGQvSU= munk@winny (actually broken up so it displays properly here, usually a single line) Ensure the ~/.ssh/authorized_keys file is readable only by the user: CODE: chmod 600 ~/.ssh/authorized_keys Finally, tell Putty to use the private key for all SSH sessions with the remote server. This is done by selecting the session settings in putty for the server that has the public key, clicking 'Load', selecting the 'Connection, SSH, Auth' setting page and then selecting the private key file on that page using the Browse button. Save the settings by going back to the 'Session' page tab and hitting 'Save'. If all went well and the private key was created without using a password phrase, this should allow you to login to the remote server without the need for a password. However IMPORTANTLY it should be stressed for obvious reasons using no passphrase to protect the private key should only be contemplated on a machine on which you know noone else uses or has access to - either physically or across a network. I feel like a dirty security whore in a way for even suggesting not using a security passphrase for the private key, but the truth of it is noone has physical access to this machine who would care about accessing my servers so ... I'm off to setup a passphrase now... :)
(Page 1 of 1, totaling 4 entries)
|

