LOGINFAILURE.PL - Block IPs where failed login attempts originate

Download this program

SYNOPSIS

    loginfailure.pl -summary            # Show failing IPs
    loginfailure.pl -denyip 192.168.1.4     # Block this IP
    loginfailure.pl -allowip 192.168.1.4    # Stop blocking this IP
    loginfailure.pl /var/log/messages   # Check file for offending IPs
    
    loginfailure.pl -daemon 60 /var/log/secure
    loginfailure.pl -failures 4 -daemon 60 /var/log/secure*


DESCRIPTION

Many times production Unix machines cannot restrict login access by IP address. This allows crackers to attempt to break in by repeated login attempts with various passwords.

This program was written to help identify those cracking attempts and block the intruder. This is accomplished by reading the system log file, collecting a list of the IP addresses from which such login attempts were made and then adding their IP addresses to /etc/hosts.deny. After a period of time the hosts.deny is rewritten, removing the addresses which were blocked.

This program typically runs as a daemon, frequently reading the log files, updating its tables and when necessary, rewriting the hosts.deny file.

Alternatively, the program may be run as a cron entry. This latter mode, of course, only notices attacks when the cron job is run, whereas in daemon mode the program will notice the attack within a much shorter period.

The idea behind this program is that once an IP address is found to have enough login failures, you want to block it for a relatively short period (-denytime) and then later unblock the IP address (-purgetime).

If there are more login failures, the program can notice them quickly (especially in -daemon mode) and block the IP address again. If you don't eventually unblock, you will block hundreds of IP addresses which are no longer a threat, wasting processing time.

If someone tries to login from a multi-user system or a legitimate user's laptop which had a virus and is now cleaned up, you may end up blocking a legitimate user. Blocking an IP permanently just makes it very confusing and difficult to get legitimate IP addresses unblocked. By unblocking them after some period of time, you give legitimate users access again. In general the task is to balance restricting access with staying open for legitimate users.

Some systems will have very little access and only from very few places and so setting a high -denytime value and small -failures value makes sense. Other open multi-user systems will need a less restrictive approach.


OPTIONS

-allowip ip

Specifies an IP address (e.g. x.x.x.x) to be added to the database and be blocked.

-daemon S

Specifies the program should run in daemon mode and recheck the log files every S seconds. The program does not parse the entire file each time, but picks up where it left off the last time. The default is 0 seconds (no daemon mode).

-db file

Specifies the location of the database maintained by this program. The default is /var/lib/loginfailure/loginfailure.db.

-denyip ip

Specifies an IP address (e.g. x.x.x.x) to be removed from the database and no longer be blocked.

-denytime TIME

Specifies the amount of time IP address should remain blocked. The default is 20m. TIME may be specified as a decimal number plus a letter:

  N or Ns- number of seconds
  Nm - number of minutes
  Nh - number of hours
  Nd - number of days
-detail

Use this to see all of the information in the database. This implies -summary.

-etcdeny file

Specifies the location of the deny file, only useful for testing. The default is /etc/hosts.deny.

-failures N

Specifies the maximum number of login attempts to be tolerated (e.g. N-1) from this IP address in the -daemon interval.

-help

Shows this help text.

-ip 'ip1[,ip2,... ipN]'

Specifies a comma delimited list of IP addresses which will not be blocked. The IP address may be specified as a full IP address, e.g. 192.168.1.5, or with '*' characters meaning to block a range of IP addresses See examples in SETUP CONSIDERATIONS. Rather than stop this program from blocking some set of IP addresses, consider adding the IP addresses (or domains) to /etc/hosts.allow.

-logfile file

Specify this as the place where messages will be logged. This only applies when using -daemon. You may want to use logrotate to manage the log file. The default is /var/log/logfailure.log.

-nofork

Specify this when you use -daemon, but do not actually want the program running in the background. This is only useful for development.

-purgetime TIME

IP addresses will be kept in the database until they expire (are older then TIME). The default is 1d. TIME may have the same values as -denytime, but should be longer than -denytime.

-summary

Use this to see a short summary of the IP addresses in the database which have been candidates for blocking. Note that this list contains all IP address (younger than -purgetime) and can contain IP address that are no longer blocked.

-verbose N

Specifies the amount of information written to STDERR regarding the processing being done. The default is 0.


PARAMETERS

logfile .. logfileN

Specifies the log file(s) to be read. These files can be read if they were compressed with gzip (e.g. have an extension of .gz). Typically this is /var/log/secure, but might be /var/log/messages or /var/log/auth.log or others depending on your installation.


SETUP CONSIDERATIONS

The administrator should add IP addresses which should never be blocked to @IPDONOTDISABLE. The local host name IP address will normally be determined automatically, but if your machine has multiple IP addresses, you should add the correct local IP addresses to this array.

You may also specify IP addresses which should be blocked by passing them with the -ip option.

Addresses in @IPDONOTDISABLE may be specified as conventional full IP addresses (e.g. x.x.x.x) or with a pseudo 'mask' character '*'. Some examples should clarify this:

 127.0.0.1    - matches only 127.0.0.1
 192.168.1.*  - matches 192.168.1.0   through 192.168.1.255
 192.168.1*.* - matches 192.168.10.0  through 192.168.19.255
                OR      192.168.100.0 through 192.168.199.255

/etc/hosts.deny must already exist, it will not be created. You should backup your original /etc/hosts.deny file.

This program keeps a simple database in /var/lib/loginfailure. The database can be removed if it is out of sync somehow. To get back in sync, run this program in non-daemon mode and let it process past security logs so it can rebuild it's database.

The following options should be reviewed and set according to the needs of your installation:

  -denytime
  -purgetime
  -failures
  -daemon

Note that the check is not against a particular IP and userid combination, but simple against the IP address. If '-failures 4' is specified and one user attempts to login 3 times and then another fails twice, the IP address will be blocked. The number of total failures is counted within the -denytime interval.

The hosts.deny file will be appended to so you may continue to put fixed entries in this file, as usual. Entries written by this program will be appended to file so you should be careful to not modify the file after the LOGINFAILURES comment.

This program identifies failed login attempts by parsing log entries. Only a few key log entries are checked in the subroutine ReadLog(). You may find it necessary to add your own code there to check cases this program missed. If you do this, please notify the author so others can benefit.


EXAMPLE - DAEMON MODE

The following is a commented example of running in daemon mode on a system which has access highly restricted:

cp -p /etc/hosts.deny /etc/hosts.deny.master

Make a copy of your original hosts.deny.

cp -p loginfailure.pl /usr/local/sbin/loginfailure.pl

Install this program.

mkdir /var/lib/loginfailure

Create a place for the database. Be sure to specify an alternative path with -db pathtofile.

vi /etc/rc.local

Set up your system to launch this program at boot time. Obviously, you can start this as part of any other system startup script. You will like want to use the same command shown at the end of this section.

perl -MCPAN -e shell install Date::Parse

This program requires your machine have the Perl package Date::Parse installed. The commands shown here would allow you to install the Perl package yourself.

/usr/local/sbin/loginfailure.pl -denytime 4d -failures 1 -daemon 0 /var/log/secure*

The first time you should run this program on all log files of interest (e.g. /var/log/secure*) so that it finds all the past intruders who should be blocked. The database will be purged based on the -denytime TIME option. This will also show other set up errors and could modify /etc/hosts.deny.

/usr/local/sbin/loginfailure.pl -denytime 4d -failures 1 -daemon 60 /var/log/secure

Now start the program in daemon mode. Use this command in your rc.local file. Lines will be appended to the log file. Watch the log file and your security log file for problems to make sure this program finds all the improper login attempts. See also MESSAGE LOGGING.


EXAMPLE - CRONTAB MODE

There are only a few differences between running this program as a daemon versus running it manually or via a crontab entry. The set up is the same for both see EXAMPLE - DAEMON MODE, above with the exception that the value passed on the -daemon option should be 0 (zero) and rather than setting up rc.local, you should invoke this program via crontab.

When running in this mode, the entire security file will be parsed each time, meaning it will run longer than in daemon mode (still taking only a few seconds typically). Of course the program will only detect invalid login attempts each time it runs, so if you run this once an hour, then your system will be slower in blocking intruders. See also MESSAGE LOGGING.


MESSAGE LOGGING

The log file attempts to summarize all relevent activity. The hosts.deny file is only written when there is a change in the status of some IP address.

Each time a new IP address is to be blocked, you see a logfile entry and a new hosts.deny is created. See the option -denytime.

Each time a blocked IP address expires and is no longer to be blocked, you see a logfile entry and a new hosts.deny is created. See the option -purgetime.

A sample log file follows. Notice how IP addresses are added and later removed.

  2007/01/09 08:08 loginfailure.pl now in daemon mode
  2007/01/09 08:08 Using database '/var/lib/loginfailure/loginfailure.db'
  2007/01/09 20:37 Now blocking '87.2.240.240'
  2007/01/09 20:37 Rewrote '/etc/hosts.deny' stopping 11 IP addresses 
  2007/01/09 21:01 No longer blocking '207.44.172.21'
  2007/01/09 21:01 Rewrote '/etc/hosts.deny' stopping 10 IP addresses 
  2007/01/13 18:41 Now blocking '202.46.68.130'
  2007/01/13 18:41 Rewrote '/etc/hosts.deny' stopping 6 IP addresses
  2007/01/13 20:37 No longer blocking '87.2.240.240'
  2007/01/13 20:37 Rewrote '/etc/hosts.deny' stopping 5 IP addresses
  2007/01/15 01:29 Now blocking '207.36.86.25'
  2007/01/15 01:29 Rewrote '/etc/hosts.deny' stopping 8 IP addresses
  2007/01/17 18:43 No longer blocking '202.46.68.130'
  2007/01/17 18:43 Rewrote '/etc/hosts.deny' stopping 9 IP addresses


EXIT

If no fatal errors are detected, the program exits with a return code of 0. Any error will set a non-zero return code. If running in daemon mode, the program will exit, but a child process continues to execute.


AUTHOR

Originally written by Terry Gliedt <tpg@hps.com> in 2007 and is made available under terms of the GNU General Public License.