cipherdyne.org

Michael Rash, Security Researcher



Chapter 8: Active Response with psad

No treatment of intrusion detection would be complete without a discussion of options for automatically responding to attacks. The response capabilities offered by psad are built on top of a clean interface that makes it easy to integrate with third-party software, and an example of integrating with the Swatch project is included in this chapter.

Chapter 8 discusses a custom perl script sshauth.pl (see below) that leverages psad to add iptables blocking rules against an attacker after a configurable number of failed login attempts are logged via SSHD from the same IP address. Once psad has blocked the attacker, it manages the iptables policy to ensure that the rules are removed after the appropriate timeout (so an external script does not have to build in this functionality), and blocking rules are added to all three of the INPUT, OUTPUT, and FORWARD chains.

#!/usr/bin/perl -w
#
#############################################################################
#
# File: sshauth.pl
#
# Purpose: To interface with psad to block IP addresses that commit failed
#          login attempts against SSHD.  This script was written for the
#          book "Linux Firewalls: Attack Detection and Response with
#          iptables, psad, and fwsnort".
#
# Copyright (C) 2006-2007 Michael Rash (mbr@cipherdyne.org)
#
# License (GNU Public License):
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
#   USA
#
#
#############################################################################
#
# $Id: index.html 2980 2011-01-09 15:27:41Z mbr $
#

use IO::Socket;
use IO::Handle;
use strict;

#============== config ===============
my $auth_failed_threshold = 2;
my $auth_failed_regex =
    'sshd.*Authentication\s*failure.*?((?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2})';
my $sockfile = '/var/run/psad/auto_ipt.sock';
my $sleep_interval = 5;  ### seconds
#============ end config =============

### cache previously seen IP addresses and associated failed login
### counts
my %ip_cache = ();

### open the psad domain socket for writing
my $psad_sock = IO::Socket::UNIX->new($sockfile)
    or die "[*] Could not acquire psad domain ",
        "socket $sockfile: $!";

my $file = $ARGV[0] or die "$0 <file>";

### open the log file
open F, $file or die "[*] Could not open $file: $!";
my $skip_first_loop = 0;
for (;;) {
    unless ($skip_first_loop) {
        seek F,0,2; ### seek to the end of the file
            $skip_first_loop = 1;
    }
    my @messages = <F>;
    for my $msg (@messages) {
        if ($msg =~ m|$auth_failed_regex|) {
            $ip_cache{$1}++;
        }
    }
    for my $src (keys %ip_cache) {
        ### block the IP if the threshold is exceeded
        if ($ip_cache{$src} % $auth_failed_threshold == 0) {
            print $psad_sock "add $src\n";
        }
    }
    F->clearerr();  ### be ready for new data
    sleep $sleep_interval;
}
close F;
close $psad_sock;
exit 0;