Below (and atached) is a script I wrote do exactly what you are talking about.
It's commented, so edit to your taste. I have been using to for about 4 months.

Since I am using PF as my firewall, it is customized for that. If you
are using something other then PF, again... edit to your taste.

-Erik-

#!/usr/bin/perl
# created by [EMAIL PROTECTED] 03/05

my $time=localtime();

use strict;
use Time::localtime;
use Mail::Send;

my $hostname="domain.orIP.com";

#The white list that contains either the account or host.
my $whilelist="/home/user/scripts/sshwhitelist";

#LOG to search on
my $logfile="/var/log/auth.log";

#Where to read the current list of blackhole address.
my $blacklist="/etc/pf.blackholes";

#Name of the table in your pf.conf
my $tablename="blackhole";

#Where to store the cache file. This is removed and updated daily
my $cache="/root/.sshprotect.cache";

#Where to log actions taken.
my $log="/root/sshprotect.log";

#Command you want to run in response of a potential attack.
my $command="whois";
my $useip=1;  #useful in conjunction with $command which will do
something with the IP.
            #comment out if not needed.

#Max attempts a host can have until blocked.
my $attempts=5;

# Set this to "run" the $command or "print" a report or "email" the report,
# also "update" will update the $blacklist and reload the blackholes table.
# "abuse" will try to find and email the offending network about the attack
# These can be combind to run all actions:
#my $action="run print";
#my $action="print";
my $action="email run update abuse";
#my $action="print email update";
#my $action="print email";

#Email setup;
my $to="[EMAIL PROTECTED]";
my $from="[EMAIL PROTECTED]";
my $cc="";
my $subject="Excesssive login attempts";


my $debug=0;

my $host;
my @logs;
my @whtlst;
my %track;
my @blacklist;
my $block=1;
my @abuse;
my @cache;
my $currentcache;
my @runoutput;

my $version="1.2.1beta";
print "Version: $version\n" if $debug;

#find todays datemask
use vars qw($yr $mon $day $today $mday);
$yr=localtime->year() + 1900;
$mon=localtime->mon() + 1;
$mday=localtime->mday();
if ($mon != /\d\d/) {$mon="0$mon";}
if ($mday < 10) {$mday="0$mday";}
$today="$yr$mon$mday";
print "$today\n" if $debug;
#no Time::localtime;

open (WRITELOG, ">> $log") || die "$log $!\n";

open (BLACK,$blacklist) || die "$blacklist $!\n";
while (<BLACK>) {
  chomp;
  push (@blacklist, $_);
}
close BLACK;

open (WHITE, $whilelist) || die "$whilelist $!\n";
while (<WHITE>) {
  chomp;
  push (@whtlst,$_);
}
close WHITE;

open (READCACHE, $cache) || print "$cache $!\n";
while (<READCACHE>) {
  chomp;
  push (@cache, $_);
}
close READCACHE;

open (WRITECACHE, ">> $cache") || print "$cache $!\n";

if (@cache[0] < $today) {
  close WRITECACHE;
  system ("rm -f $cache");
  open (WRITECACHE, ">> $cache") || print "$cache $!\n";
  print "Cache file is out of date @cache[0] < $today\n" if $debug;
  @cache=();
  print WRITECACHE "$today\n"
}

open (LOG, $logfile) || die "logfile $!";
while (<LOG>) {
  chomp;

  if (
    /Failed password for illegal user (.*) from (.*) port/
    || /Failed password for (.*) from (.*) port/
    || /Illegal user (.*) from (.*)/
    || /Did not (receive) identification string from (.*)/
     ) {

    my $account=$1;
    my $host=$2;

    ckwhtlst($account, $host);
    if ($block == 0 ) { next; }
    ckcache($host);
    if ($block == 0 ) { next; }
    ckblklst($host);
    if ($block == 0 ) { next; }
    $block=1;
    if ($track{$host}) {
      $track{$host}=$track{$host}+1;
      print "$host is now $track{$host} user=$account\n" if $debug;
    } else { $track{$host}=1; }
  }
}
close LOG;

for my $host (%track) {
  if (!$host) {print "Nothing Found\n"; exit;}
  if ($track{$host} >= $attempts) {
    push (@abuse,$host);
    ckcache($host);
    print WRITECACHE "$host\n" if !$block == 0;
    if ($action =~ /print/) { print "Host $host, past $attempts
attempted logins\n"; }
    if ($action =~ /run/ && $useip) { (@runoutput=`$command $host`); }
    if ($action =~ /run/ && !$useip) { (@runoutput=`$command`); }
    if ($action =~ /update/) { update($host); }
  }
}


#Sends emails
if ($action !~/email/) {
  exit;
} elsif (@abuse) {
  send_email(@abuse);
}

if ($action !~/abuse/) {
  exit;
} elsif (@abuse) {
  abuse_email(@abuse);
}

sub ckwhtlst {
  (my $account, my $host)[EMAIL PROTECTED];
  foreach (@whtlst) {
    if (!/$account|$host/) {
      $block=1;
      return;
    } else {
      print "$host or $account is on the while list.\n" if $debug;
      $block=0;
      return;
    }
  }
}

sub ckblklst {
  my [EMAIL PROTECTED];
  foreach (@blacklist) {
    if (/$host/) {
     print "$host $_ is already blacklisted\n" if $debug;
      $block=0;
      return;
    } else { $block=1; } #print "$host is NOT blacklisted\n" if $debug; }
  }
}
sub ckcache {
  my [EMAIL PROTECTED];
  if ([EMAIL PROTECTED]) { $block=1; return;}
  foreach (@cache) {
    if (/$host/) {
      $block=0;
      print "$host is already cached\n" if $debug;
      return;
    } else { $block=1; } #print "$host is not found in cache\n" if $debug; }
  }
}

sub update {
  open (OUT, ">> $blacklist") || die "$blacklist $!\n";
  print OUT "@_[0]\n";
  system ("pfctl -t $tablename -f /etc/pf.conf");
  close OUT;
}

sub send_email {
  my $subject="$subject $today";
  my $msg = new Mail::Send;
  my $host;
  $msg->subject($subject);
  $msg->to($to);
  $msg->cc($cc) if $cc;
  $msg->add("From", "$from");
  $msg->add("Return-Path", "$from");
  $msg->add("Reply-To", "$from");

  my $fh=$msg->open;

  foreach (@_) {
    $host=$_;
    if (!$track{$_}) {return;}
    print $fh "\nThe host $_ has $track{$_} attempted logins.\n";
  }
  print $fh "\nThe threshold is set to $attempts attempts\n";
  print $fh "\nActions taken: $action\n\n";
  if (($action =~/run/ && $command) && !$useip) { print $fh "Ran:
$command\n\n Output:[EMAIL PROTECTED]"; }
  if (($action =~/run/ && $command) && $useip) { print $fh "Ran:
$command $host,\n\n Output:[EMAIL PROTECTED]"; }

  print $fh "\nVersion: $version\n";
  print "Sending email\n" if $debug;
  print WRITELOG "$time Sent email to $to about $_ \"$subject\"\n";
  $fh->close;
}

sub abuse_email {
  $subject="[ABUSE] $subject $today";
  my $msg;
  my $fh;
  my $acct;
  my $domain;

  foreach my $ip (@_) {
    my $syntax="$ip SOA";
    if (!$track{$ip}) {return;}
    if (~/\d{1,3\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { $syntax="-x $ip SOA"; }

    print "Running dig $syntax\n" if $debug;
    my @dig=`/usr/bin/dig $syntax`;

    foreach my $dig (@dig) {
      if ($dig =~ /in-addr\.arpa\..*SOA\t.*\. (.*)\./) {
        my $addy=$1;
        if (!$addy) { next; }
        if ($addy =~ /(\w+)\.(.+)/) {
          $acct=$1;
          $domain=$2;
        }
        $to="[EMAIL PROTECTED]";

        print "Found $to from Dig\n" if $debug;

        $msg = new Mail::Send;
        $msg->subject($subject);
        $msg->to($to);
        $msg->cc($cc) if $cc;
        $msg->add("From", "$from");
        $msg->add("Return-Path", "$from");
        $msg->add("Reply-To", "$from");
        $fh=$msg->open;
        print $fh "\nThis host $ip has attempted $track{$ip} erroneous
ssh logins to my server $hostname on $today.\n";
        print $fh "Please report this to your customer and advise them
on any AUP violations you enforce.\n";
        print $fh "\n\nThank you\nErik\n";

        print $fh "\nVersion: $version\n" if $debug;
        print "Sending abuse email to $to\n" if $debug;
        print WRITELOG "$time ABUSE:Sent email to $to about $ip\n";
        $fh->close;

      }

    }

  }

}

close WRITECACHE;
close LOG;

use Data::Dumper;
print Dumper %track if $debug;


On 7/1/05, John Cholewa <[EMAIL PROTECTED]> wrote:
> Jun 30 10:36:05 phantom sshd[70478]: Failed password for news from 
> 212.88.182.121 port 51218 ssh2
> Jun 30 10:36:16 phantom sshd[70500]: Failed password for sshd from 
> 212.88.182.121 port 51608 ssh2
> Jun 30 10:36:39 phantom sshd[70569]: Failed password for root from 
> 212.88.182.121 port 52297 ssh2
> 
> I get the above a lot in my logs (except more of it).  Each day, a couple 
> hundred failed attempts to log in from one or sometimes two IP addresses 
> shows up.  I don't have anything like ipf running, and since this machine is 
> about fifteen hundred miles away from me, I don't want to experiment with 
> software firewalling right now.
> 
> That known, is there any way to tell sshd (or some more powerful daemon) to 
> stop accepting login attempts from a given IP if it tries and fails to log in 
> too many times in a limited duration (like in the same minute)?
> 
> I suppose, now that I'm thinking about it, that it'd be best to actually just 
> read the man pages and figure out how to get sshd to ignore any attempt to 
> attach from ports other than 22.  I mean, why are other machines trying to 
> ssh in at ports over fifty thousand anyway?
> 
> --
>   -JC
>   http://www.livejournal.com/users/jcholewa/
> 
> PS:  Oh, yeah ... "FreeBSD 4.8-RELEASE #0: Thu Apr  3 10:53:38 GMT 2003" ; 
> openssh-3.6.1_5 ; openssl-0.9.7d_1
> 
> 
> 
> _______________________________________________
> freebsd-questions@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-questions
> To unsubscribe, send any mail to "[EMAIL PROTECTED]"
>

Attachment: sshprotect.pl
Description: Binary data

_______________________________________________
freebsd-questions@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-questions
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to