#!/bin/bash
#
# Copyright (C) 2010 Emanuele Tomasi <spina80@gmail.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

###
# Last update: 02/06/2010
# by Spina <spina80@gmail.com>
#
# Monitora il file di log del demone sshd e inserisce gli IP che 
# tentano un brute force in un file.
#
# Pensato per monitorare il file /var/log/messages ed inserire i 
# tentativi di brute force via ssh in un file di blacklist tipo 
# /etc/hosts.deny per il server tcp wrapper "tcpd".
#
# NOTE: I comandi "tail" della suite coreutils < 7.5 usano la 
#       system call "nanosleep", la quale fa degradare le performace.
#       E' vivamente consigliato usare i "tail" della suite coreutils >= 7.5 
#       la quale usa invece la SC inotify sui kernel >= 2.6.21.
#
###

### USER CONFIG ###

LOG_FILE=/var/log/messages   # File da monitorare
ERROR_TRY_TO_BL=6            # Tentativi consecutivi sbagliati prima di mettere
                             # l'ip in blacklist
SECOND_TO_RESET_COUNT=300    # Se passano più di questi secondi dal primo 
                             # tentativo, il contatore viene resettato, in 
                             # questo modo un utente umano può fare tot 
                             # tentativi ogni SECOND_TO_RESET_COUNT
OUTPUT_FILE=/etc/hosts.deny  # File di blacklist in cui mettere gli ip che 
                             # tentato il brute force
### END USER CONFIG ###

### SCRIPT BEGIN ###
old_ip='fake_ip'         # IP della macchina che ha sbagliato il login
ip_consecutive_entry=1   # Contatore dei tentativi consecutivi falliti
date_first_try=0         # Data del primo tentativo fallito
touch $OUTPUT_FILE
if which logger >& /dev/null
then
    logger=logger
    logger_opt="-p authpriv.warn -t ${0##*/}[$$]"
else
    logger=echo
    logger_opt="${0##*/}[$$]: "
fi

# Questa variabile viene usata per filtrare gli ip che hanno sbagliato l'accesso.
# Viene usata da sed e DEVE filtrare la riga del log per far uscire SOLO l'ip.
regex_filter='/Failed/b print;/Invalid/b print;d;:print s/^.*from[[:space:]]*\([[:digit:]\.\:]\+\).*/\1/'

# Inizia il monitoraggio
/bin/tail -n +1 --follow=name --retry $LOG_FILE 2>/dev/null | while read line
do
    ip=$(echo $line | sed "$regex_filter")
    if [[ ${ip} != "" ]]
    then
	date_try=$(date -d"$(echo $line | tr -s ' ' | cut -d' ' -f1-3)" '+%s')
	if [[ $ip == $old_ip ]]
	then
	    if (( $date_try - $date_first_try >= $SECOND_TO_RESET_COUNT ))
	    then
		ip_consecutive_entry=1
		date_first_try=$date_try
		continue
	    fi
	    let ip_consecutive_entry++
            if (( $ip_consecutive_entry ==  $ERROR_TRY_TO_BL )) && ! grep -q $ip $OUTPUT_FILE
	    then
		$logger $logger_opt "blacklisted brute force from $ip"
		echo $ip >> $OUTPUT_FILE
	    fi
	else
	    date_first_try=$date_try
            ip_consecutive_entry=1
	    old_ip=$ip
	fi
    fi
done
### SCRIPT END ###
