#!/usr/bin/perl # This script watches the /var/log/secure for failed ssh attempts. Wh +en found, it will add a reject route to your routing table, making it + impossible for your machine to communicate with that host again. # # Written By: Matt Joubert (matt __at__ uucp _dot_ ca) # Date: June 2, 2006 # use strict; use warnings; use Sys::Syslog; # define ssh log file location my $logFile = '/var/log/secure'; # syslog facility my $syslogFac = 'local0'; # syslog level my $syslogLevel = 'info'; # SAFE IPS, NEVER BLOCK (I sometimes forget a password..) my @safe = qw/ 192.168.0.1 /; # define threshold in minutes to reset the failed attempt counter # note, this shouldn't be nuts because if set to high, you could shoot + yourself in the foot my $thresHold = 10; # minutes my $maxAttempts = 5; ##### Probably wont need to change anything below ##### use File::Tail; use Time::ParseDate; $thresHold *= 60; # convert to seconds; my $fh = File::Tail->new( name => $logFile, maxinterval => 10, interval => 10, adjustafter => 5 ) || die ("could not open log file: $!"); # at this point, the file is open.. so the rest should be able to work + fine in fork. defined(my $pid = fork) or die "Can't fork: $!"; exit if $pid; my %db; my @rejects; while ( my $line = $fh->read ) { # ignore all lines except for the failed ones next unless $line =~ /Failed password/ig; my @column = split ( /\s+/, $line ); # grab the IP address $line =~ m/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/g; my $ip = $1; next unless $ip; next if safe( $ip, @safe ); my ( $mon, $day, $time ) = (@column)[ 0, 1, 2 ]; my $epoch = parsedate("$mon $day $time"); if ( !defined( $db{$ip} ) ) { push ( @{ $db{$ip} }, $epoch ); } else { push ( @{ $db{$ip} }, $epoch ); # past threshold.. start over from scratch if ( $db{$ip}[ $#{ $db{$ip} } ] - $db{$ip}[ $#{ $db{$ip} } - 1 + ] > $thresHold ) { undef( $db{$ip} ); push ( @{ $db{$ip} }, $epoch ); } else { # threshold is good - check for attempts if ( scalar @{ $db{$ip} } > $maxAttempts ) { if ( !isRejected( $ip, @rejects ) ) { push ( @rejects, $ip ); syslog("$syslogLevel|$syslogFac", "Adding $ip to r +eject route table for too many failed attempts"); system("/sbin/route add -host $ip reject"); } } } } } # check if ip is "safe" from being blocked sub safe { my $ip = shift; my @safe = @_; foreach (@safe) { return 1 if $ip eq $_; } return 0; } # check if ip has alread been recently reacted too sub isRejected { my $ip = shift; my @rejects = @_; foreach (@rejects) { return 1 if $ip eq $_; } return 0; }

In reply to SSH Failed Attempt Monitor by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.