Welcome to Deadbeef.com
Articles and tips on software from authored by Jeremy Bettis.

Search

XML Feed RSS

What is RSS?

Who's Online?

  • Guest Users: 21

Auto-blocking and emailing hosts that attack via ssh or ftp

01/23/06

Permalink 03:33:04 pm, by Jeremy Email , 674 words, 7960 views   English (US)
Categories: Unix, Security

Auto-blocking and emailing hosts that attack via ssh or ftp

I have written a script, which is intended to be run from cron every few minutes, which will block hosts that try dictionary attacks on your unix server. You will need to tweak this for your own use.

The script sends an email to the network administrator, then adds the ip address to /etc/hosts.deny.

It works for me, but your mileage may vary. Uses: mutt, ntpstat and the whois service at whois.deadbeef.com

This is three scripts.

auto_send_ssh_complaints: Scans log files for attacks, and invokes the proper script to send the email.

#!/bin/sh

# Fill in your own whitelisted hosts here
whitelist="127.0.0.1 1.2.3.4 `host home.example.com | sed -e 's/[^0-9]*//'`"

sed -e '/sshd\[[0-9]*\]: Failed password/!d' \
        -e 's/.*Failed password for.*from //' \
        -e 's/ port.*//' /var/log/secure | sort | uniq -c | \
while read info
do
set -- $info
count=$1
host=$2
whitelisted=0

host=`echo $host | sed -e 's/::ffff://'`

number_of_usernames=`sed -e '/sshd\[[0-9]*\]: Failed password.*from '$host'/!d' -e 's/.*Failed password for //' -e 's/ from .*//' /var/log/secure  | sort -u | wc -l`

for white in $whitelist ; do
        if [ "$white" = "$host" ] ; then
                whitelisted=1
        fi
done

if [ "$whitelisted" = "1" ] ; then
        echo "$count attempts from WHITELISTED $host"
elif grep -q "ALL:$host" /etc/hosts.deny ; then
        : #echo "$host is blacklisted"
else
        #echo "$count attempts from $host"
        #host $host
        if [ "$count" -gt "14" -o "$number_of_usernames" -gt "4" ] ; then
                /root/bin/ssh_complain $host
        else
        :       #echo "WARNING: $host is not blacklisted"
        fi
fi
done

sed -e '/vsftpd(pam_unix)\[[0-9]*\]: authentication failure/!d' \
        -e 's/.*rhost=.*from //' \
        -e 's/ user=.*//' /var/log/messages | sort | uniq -c | \
while read info
do
set -- $info
count=$1
host=$2
whitelisted=0

for white in $whitelist ; do
        if [ "$white" = "$host" ] ; then
                whitelisted=1
        fi
done

if [ "$whitelisted" = "1" ] ; then
        echo "$count attempts from WHITELISTED $host"
elif grep -q "ALL:$host" /etc/hosts.deny ; then
        : #echo "$host is blacklisted"
else
        #echo "$count attempts from $host"
        #host $host
        if [ "$count" -gt "25" ] ; then
                /root/bin/ftp_complain $host
        else
        :       #echo "WARNING: $host is not blacklisted"
        fi
fi
done

ftp_complain: Sends email about ftp attacks.

#!/bin/sh

while [ "$1" != "" ] ; do
        ipaddr=$1
        shift

        echo "Sending FTP complaint on $ipaddr"

        echo "Getting email addresses"
        emails="`whois "$ipaddr@whois.deadbeef.com" | awk '/^[^\[]/ {print $1}'`"

        echo "Getting logs"
        fgrep "$ipaddr" /var/log/secure* /var/log/messages* >$ipaddr.txt

        echo "Getting count"
        count=`grep 'vsftpd.*authentication failure.*rhost='"$ipaddr" /var/log/messages* | wc -l | sed 's/ *//'`
        echo "Count=$count"

        if [ "$emails" = "" ]  ; then
                echo "No email addresses"
        else
                echo "Sending email"
                cat <<EOF | mutt -a $ipaddr.txt -s "Excessive FTP attempts from $ipaddr" $emails root@example.com
My host server.example.com (1.2.3.4) has received roughly $count
attempts to login via the FTP protocol from your host at $ipaddr.  I have
attached the relevant portions of my logfiles.  All times are in CST/CDT.

`ntpstat`

Thank you for your understanding.
admin@example.com
EOF
        fi

        if grep "^ALL:$ipaddr\$" /etc/hosts.deny ; then
                echo "Already in blocked list"
        else
                echo "Adding $ipaddr to blocked list"
                echo "ALL:$ipaddr" >>/etc/hosts.deny
        fi
done

ssh_complain: Sends email about ssh attacks

#!/bin/sh

cd /tmp

while [ "$1" != "" ] ; do
        ipaddr=$1
        shift

        echo "Sending SSH complaint on $ipaddr"

        echo "Getting email addresses"
        emails="`whois "$ipaddr@whois.deadbeef.com" | awk '/^[^\[]/ {print $1}'`"

        echo "Getting logs"
        fgrep "$ipaddr" /var/log/secure* /var/log/messages* >$ipaddr.txt

        echo "Getting count"
        count=`grep 'Failed password for.*from '"$ipaddr"'.*ssh2' /var/log/secure* | wc -l | sed 's/ *//'`
        echo "Count=$count"

        if [ "$emails" = "" ]  ; then
                echo "No email addresses"
        else
                echo "Sending email"
                cat <<EOF | mutt -a $ipaddr.txt -s "Excessive SSH attempts from $ipaddr" $emails root@sageconspiracy.com
My host server.example.com (1.2.3.4) has received roughly $count
attempts to login via the SSH protocol from your host at $ipaddr.  I have
attached the relevant portions of my logfiles.  All times are in CST/CDT.

`ntpstat`

Thank you for your understanding.
admin@example.com
EOF
        fi

        if grep "^ALL:$ipaddr\$" /etc/hosts.deny ; then
                echo "Already in blocked list"
        else
                echo "Adding $ipaddr to blocked list"
                echo "ALL:$ipaddr" >>/etc/hosts.deny
        fi
done

Comments, Pingbacks:

Comment from: Tony Paletti [Visitor] Email
I have the following on my system:

/etc/cron.d
/etc/cron.daily
/etc/cron.hourly
/etc/cron.monthly
/etc/cron.weekly

Where do I put those scripts to ensure they are run every few minutes?

Thanks in advance!
PermalinkPermalink 08/06/06 @ 14:39
Comment from: Jeremy [Member] Email · http://www.deadbeef.com
Here is what I did:
As root, run the command:
crontab -e

This will launch vi (or your $EDITOR) and then add this line to the end:
44 */3 * * * /root/bin/auto_send_ssh_complaints


This runs the script every 3 hours at 44 minutes past the hour.

However I don't use this very much since SSHDFilter seems to to a better job.
PermalinkPermalink 08/06/06 @ 16:31
Comment from: Tony Paletti [Visitor] Email
Is there a way to test these scripts manually? I am mainly concerned with ftp_complain at the moment. I created the script file, did a chmod 744 ftp_complain, and tried testing with a ./ftp_complain. I got nothing but a prompt in response, and nothing updated in either hosts.allow or hosts.deny. There are a LOT of authentication failures showing up in my /var/log/messages file, but the I cannot seem to get the script to run manually. I am a newbie, so I apologize for my ignorance if I am not doing the obvious. Again, thanks in advance!
PermalinkPermalink 08/07/06 @ 15:09
Comment from: Jeremy [Member] Email · http://www.deadbeef.com
ftp_complain and ssh_complain don't look for attacks, they just send the message.

Test like this:

sh -x ./ftp_complain 10.0.0.1


Then when you like that one, test the log file watcher script:

sh -x ./auto_send_ssh_complaints

PermalinkPermalink 08/07/06 @ 15:19
Comment from: Firefly [Visitor] Email
Just passing through when I saw your site, Really nice work on the scripts, I think they would go well combining them with Iptables. Using the "recent" module you could create some rules that will limit the amount of attacks set to a time limit.

For an example:

# $IPTABLES -A INPUT -p tcp -i eth0 --dport 22 -m state --state NEW -m recent --name sshprobe --set -j ACCEPT
# $IPTABLES -A INPUT -p tcp -i eth0 --dport 22 -m state --state NEW -m recent --name sshprobe --update --seconds 60 --hitcount 3 -j LOG -log-prefix "SSHPROBE Violation: "

This way if the count reaches 3 in 60 seconds they will automatically get block by iptables and anything else gets sent to the logs files where your script can do it's thing.

If they don't wait 60 seconds each hit keeps resetting the TTL (time to live) on the recent module so unless they stop for atleast 60 seconds they will never get through.
PermalinkPermalink 08/21/06 @ 02:29
Comment from: Ajax 4Hire [Visitor] Email
I use denyhosts to block excessive ssh attempts with a very low setting.

My problem is with ftp; I am using vsftpd.
I would see excessive ftp login attempts.

I can enter into hosts.deny any excessive/massive ftp login attempts

-*BUT*-

vsftpd spawns a new pid for each connection.
The connection does not terminate until the cracker/hacker issues a close. This means that someone can keep the ftp port open indefinitely using the user/pass command for login attempts. Although the ipaddress is now blocked, it does not go into affect until the user stops.

I need better control over the user/pass command of vsftpd. I want it to do a 3-times-and-you-are-out login scheme like ssh where you limit the number of logon attempts.

Is there a scheme/script(s)/program that can help?
PermalinkPermalink 03/25/08 @ 08:22
Comment from: wei2ali [Visitor] Email
All thanks to Jeremy for his scripts.

I've modified the scripts to use iptables instead of hosts.deny.
I don't use SSH externally so there's no need for me to check SSH. The script checks for failed FTP login attempts every 10 minutes.
I use crontab to control the interval of checking, but you could imbed the cheking interval into the script itself.

Here's the script:


#!/bin/sh
# Fill in your own whitelisted hosts here.
whitelist="127.0.0.1 1192.168.7.2 192.168.31.145"
logfile="/var/log/messages"
# Define the checking interval through date-format.
interval=$(date | cut -b 5-15)

# Extract and count all failed login attempts. I set the threshold value of blocking to 25, which has worked very reliably.
# You can modify iptables behavior to your own liking. I simply drop all connections from the offending hosts.
grep "$interval.* failure" $logfile | sed -e '/vsftpd(pam_unix)\[[0-9]*\]: authentication failure/!d' -e 's/.*rhost=//' -e 's/ user=.*//' | sort |uniq -c | \
while read info
do
set -- $info
count=$1
host=$2
whitelisted=0
for white in $whitelist ; do
if [ "$white" = "$host" ] ; then
whitelisted=1
fi
done
if [ "$whitelisted" = "1" ] ; then
echo "$count attempt(s) from WHITELISTED $host"
else
echo "$count attempt(s) from $host"
if [ "$count" -gt "25" ] ; then
/sbin/iptables -I INPUT -s $host -j DROP
echo "Host $host blocked"
echo "iptable status:"
/sbin/iptables --list
fi
fi
done


Here's how my crontab looks like:
# Block offending hosts. Checks for attacks every 10 minutes
9,19,29,39,49,59 * * * * /bin/sh /scripts/Block
PermalinkPermalink 04/15/08 @ 04:44

Leave a comment:

Your email address will not be displayed on this site.
Your URL will be displayed.

Allowed XHTML tags: <p, ul, ol, li, dl, dt, dd, address, blockquote, ins, del, span, bdo, br, em, strong, dfn, code, samp, kdb, var, cite, abbr, acronym, q, sub, sup, tt, i, b, big, small>
(Line breaks become <br />)
(Set cookies for name, email and url)
(Allow users to contact you through a message form (your email will NOT be displayed.))

May 2008
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Sponsored Links

Categories

powered by
b2evolution