#!/bin/sh # # stop-intruder: stop waves of SSH intrusions # # Author: Adam Drzewiecki # e-mail: A.Drzewiecki@ztpnet.pl # Last modified: 13 Dec 2008 # # # Configuration # # Tolerance of login failures TOL_GENERAL="5" # Tolerance of login failures on invalid account (it should be less or equal than TOL_GENERAL) TOL_IU="2" # Generating e-mail to administrator? {yes|no} MAILING="yes" # Internet SuperServer name ISS="inetd" # # Files # # Analyzed log file LOG_FILE="/var/log/messages" # hosts.deny file HOSTS_DENY="/etc/hosts.deny" # # Common used text phrases # # SSH daemon name in the front of log lines DAEMON="sshd" # Regular expression for login failure FLD_GENERAL="Failed (password|none) for (invalid user)*" # Regular expression for invalid account login attempt FLD_IU="Failed (password|none) for invalid user" # # int main() # # There's no new information for hosts.deny UPDATED="no" # For every unique IP address of login failure... for ADDRESS in $(grep -E "$DAEMON" "$LOG_FILE" | grep -E "$FLD_GENERAL" | tr -s " " "\n" | \ grep -E "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}" | sort -u) ; do # Count login failures for this IP CNT_GENERAL="$(grep -E "$DAEMON" "$LOG_FILE" | grep -E "$FLD_GENERAL" | grep -E "$ADDRESS" | wc -l)" # Count invalid account login attempts for this IP CNT_IU="$(grep -E "$DAEMON" "$LOG_FILE" | grep -E "$FLD_IU" | grep -E "$ADDRESS" | wc -l)" # If CNT_IU or CNT_GENERAL exceeds tresholds... if [ "$CNT_IU" -gt "$TOL_IU" -o "$CNT_GENERAL" -gt "$TOL_GENERAL" ]; then # # Test whether IP isn't blocked in the hosts.deny. It must be checked because entire log file is always analysed. # if ! grep -qsE "$DAEMON[[:space:]]*[:][[:space:]]*$ADDRESS" "$HOSTS_DENY" ; then # Extract date information of the recorded event DATE=$(grep -E "$DAEMON" "$LOG_FILE" | grep -E "$FLD_GENERAL" | grep -E "$ADDRESS" | head -n 1 | tr -s " " | \ cut -d " " -f "1-3") # Ban IP in the hosts.deny file echo -n "# $DATE: detected $CNT_GENERAL login failures " >>$HOSTS_DENY echo "($CNT_IU of them into invalid accounts)" >>$HOSTS_DENY echo "# Written: $(date)" >>$HOSTS_DENY echo "$DAEMON: $ADDRESS" >>$HOSTS_DENY echo >>$HOSTS_DENY # In verbose mode... if [ "$MAILING" != "no" ] ; then # # Write an e-mail to the administrator # echo echo "$(date), script $0:" echo "On $DATE detected $CNT_GENERAL login failures from IP $ADDRESS." echo "$CNT_IU of them was attempts to login into invalid accounts." echo echo "Extract from log $LOG_FILE:" grep -E "$DAEMON" "$LOG_FILE" | grep -E "$FLD_GENERAL" | grep -E "$ADDRESS" echo echo "----------" fi # There is at least one new blocked IP address - we must re-read inetd configuration UPDATED="yes" fi fi done # Are there any new blocked IP adresses? if [ "$UPDATED" != "no" ]; then # # Sending signal SIGHUP to inetd, which force re-read configuration # killall -HUP $ISS # # In verbose mode inform administrator about sending signal to inetd # if [ "$MAILING" != "no" ] ; then echo echo "$(date): SIGHUP signal has been sent to $ISS daemon." echo fi fi