Blacklist IPs that attack SSH and FTP services on a Linux machine

I manage a Linux server (Redhat EL4, kernel version 2.6.9-34). Yesterday,  I found the server was attacked relentlessly from It seemed to be a brutal force dictionary attack. What to do then? The obvious way is to manually add that IP to host.deny, that is, append “sshd:” to /etc/host.deny in a separate line.

But that is so un-Linux and so unsustainable.

It was time to excise my bash-fu and sed-fu. The attacks were logged in /var/log/messages and looked like this (part):

sshd(pam_unix)[6548]: authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=  user=root

The idea is to periodically check (hourly by cron) the log file and find IPs with a large number (≥ 16) of unsuccessful SSH login attempts. With the following line, the IPs can be parsed out, sorted, and counted:

sed -n "/${SERVICE}.*authentication failure/ s/^.*rhost=\([0-9.]*\).*$/\1/p" "${LOGFILE}" | sort | uniq -c

where SERVICE=sshd and LOGFILE=/var/log/messages. The output is like this:


The leading numbers are counts of unsuccessful SSH login attempts, the latter are corresponding IPs. Then echo the IPs to /etc/host.deny if they are not there yet and their counts are no less than 16. Of course, I should also protect FTP service (vsftpd).  Not too hard, ha!

The following is the complete bash script (ip_block). Put it into /etc/cron.hourly and it will work for you 24/7, for free!

#! /bin/bash
# add ips with more invalid login attempts than permitted to hosts.deny
# usage: ip_block [invalid login limit, default to 16]

if [ "$EUID" -ne 0 ]
    echo " You must be root to run this script!"
    exit -1

[ "$#" -ge "1" ] && LOGIN_LIMIT="$1" || LOGIN_LIMIT=16

function add_to_list ()

    sed -n "/${SERVICE}.*authentication failure/ s/^.*rhost=\([0-9.]*\).*$/\1/p" "${LOGFILE}" | sort | uniq -c | while read line
        count=`echo $line | sed 's/  *.*$//'`
        ip=`echo $line | sed 's/[0-9]*  *//'`
        n=`grep -c -e "${SERVICE}: *$ip" "${LSTFILE}"`

        [ "$count" -ge "$MAXCOUNT" -a "$n" -eq "0" ] && echo "${SERVICE}: $ip" >> "${LSTFILE}"

add_to_list sshd   "${SYSLOG_FILE}" "${HOSTDENY_LIST}" $LOGIN_LIMIT
add_to_list vsftpd "${SYSLOG_FILE}" "${HOSTDENY_LIST}" $LOGIN_LIMIT

About Shuhua Zhang

Born in Anhui, China. Awarded a doctor's degree in electronic engineering from Tsinghua University. Now a postdoc researcher working on audio and speech signal processing, especially source separation, in gipsa-lab, Grenoble-INP, France.
This entry was posted in coding and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s