Below is a simple script I wrote to detect questionable activity and then block any IP address doing so.
It works by watching a log file, and then filtering for specific messages in the log file indicating undesirable use of my resources.
Once the offending IP address is identified, it is placed into the /etc/hosts.deny file for all tcp_wrappers aware servers to use. In my case, my SSH server is the primary service being protected here. But it could easily be any service, such as a ShoreWall blacklist file or dynamic IP firewall rules.
P.S. This is for a Fedora system, so your system may have logs in different locations and the individual lines filtered may be formatted differently. YMMV.
#!/bin/bash
#
log_file=${1:-/var/log/secure}
deny_file=${2:-/etc/hosts.deny}
touch $deny_file
#
# Abort the script if the log file has not been modified since it has been read.
builtin test ! -N $log_file && exit 0
#
function deny_ips()
{
list=${list:?}
threshold=${threshold:?}
msg=${msg:?}
echo "$list" | sort | uniq -c | while read count host
do
msg2="$msg"
[ $count -le $threshold ] && continue
ip=`echo "$host" | egrep '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'`
if [ "$host" != "$ip" ]; then
msg2="$msg2 - $host"
host=`echo "$host" | sed -e 's/ *user=.*$//'`
ip=`host $host`
if [ 0 -ne `echo "$ip" | grep 'not found' | wc -l` ]; then
(printf "# `date +"%Y-%m-%d %R"` (%s) Unable to add $msg2\n" $count) >> $deny_file
continue
fi
ip=`echo "$ip" | sed -e 's/.*has address //'`
fi
[ 0 -ne `grep -c "$ip" $deny_file` ] && continue
(printf "ALL: %12s # added `date +"%Y-%m-%d %R"` (%s $msg2)\n" "$ip" $count) >> $deny_file
done
}
threshold=3
list=`grep ': Illegal user' $log_file | sed -e 's/ */ /g' | cut -d' ' -f10`
msg='Illegal user attempts'
[ ! -z "$list" ] && deny_ips
#
threshold=0
list=`grep 'Failed password for root' $log_file | sed -e 's/ */ /g' | cut -d' ' -f11`
msg='Illegal root login attempts'
[ ! -z "$list" ] && deny_ips
#
threshold=0
list=`grep 'Failed password for illegal user root' $log_file | sed -e 's/ */ /g' | cut -d' ' -f13`
msg='Illegal user root login attempts'
[ ! -z "$list" ] && deny_ips
#
threshold=6
list=`grep 'Failed password for illegal user ' $log_file | sed -e 's/ */ /g' | cut -d' ' -f13`
msg='Failed password attempts'
[ ! -z "$list" ] && deny_ips
#
# Handle messages file
threshold=3
list=`egrep ': authentication failure; .*rhost=' $log_file | sed -e 's/.*rhost=//'`
msg='Authentication failures'
[ ! -z "$list" ] && deny_ips
Below is a script I run to clean up the logs by removing entries attributed to the IP addresses previously denied access by the above script. Since they're being blocked, there's no need to keep the potentially voluminous log records before they were shut off by the detector.
#!/bin/bash
logfile=$1
logfile=${logfile:?}
cd /var/log
if [ ! -r $logfile ]; then
echo "Logfile '/var/log/$logfile' not found."
exit 1
fi
# Extract just the IP addresses from the /etc/hosts.deny file
perl -ane 'print "$F[1]\n" if m/^ALL:/' /etc/hosts.deny | sort -n >deny.ip
# Build a list of those IP addresses found in the logfile
echo "Processing $logfile"
ls -l $logfile
ips=`grep -f deny.ip -o $logfile | sort -n | uniq`
for ip in $ips
do
echo "Cleaning $ip"
perl -p -i -e "undef \$_ if m/\\Q$ip\\E/" $logfile
ls -l $logfile
done
# Clean the DenyUsers messages
perl -p -i -e "undef \$_ if m/not allowed because listed in DenyUsers/" $logfile
perl -p -i -e "undef \$_ if m/input_userauth_request: illegal user root/" $logfile
Enjoy!