Automatically block aggressive IPs to prevent brute force or DDOS attacks using Bash and IPtables

Oct 11th, 2014 | By | Category: Internet, Linux / Freebsd

Something I do, mainly because of my ignorance of a more elegant solution, is to manually check my logs every 4 hours and the mail server logs every 2 minutes for excessive access by individual IP’s. I run a few scripts together that:

  1. Check the access.log and list off the top 10 IP’s organized by how many hits they have to the server
  2. Dump the results into a log file
  3. Have another script look at that log file and ban any IP that has hit the server more than X amount of times over the past X hours
  4. Save my iptables.save

As mentioned this might not be the most elegant solution but after running this for several months it seems to be working very well.  If you do nothing else then just setup the last script on your server and take a look at your mail logs(if you run a public facing mail server).  The results should scare you into action as your mail server is going to be getting slammed by Chinese, Iranian and Israeli traffic as bots from those country work to penetrate your defenses.  A smart thing to do from the outset is change all of your ports for ssh or ftp to nonstandard ones but there are some things that you might not be able to and this is where they’ll tunnel in.  Anyways, it only took one day of seeing the 10’s of thousands of hits from around the world to motivate me to create this little defence force of scripts to keep a vigilant guard behind the scenes.  Since I’ve put them in place my IPtables list has grown to probably 50-60, nothing huge to worry about, but the attacks have completely stopped.

Here’s what it looks like:

autoBanIPs_mail.sh

#!/bin/bash

# This script checks the last 2 minutes of log entries to see if any 
# IP has made over 99 connections

now=$(date +"%m_%d_%Y")

/root/bin/checkBadIPs_mail.sh > /home/ipChecker/ipcheckMAIL_$now.txt
cat /home/ipChecker/ipcheckMAIL_$now.txt | \
    grep " \\(\\([9][9]\\)\\|\\([0-9][0-9][0-9]\\+\\)\\) " | \
    awk '{print $2}' > /home/ipChecker/badMailIPs_$now.sh
sed -i "s/^/\/usr\/local\/sbin\/blockIP /g" /home/ipChecker/badMailIPs_$now.sh
/bin/bash /home/ipChecker/badMailIPs_$now.sh
cat /home/ipChecker/ipcheckMAIL_$now.txt >> /home/ipChecker/ipcheckMAIL_$now.log
rm /home/ipChecker/ipcheckMAIL_$now.txt
rm /home/ipChecker/badMailIPs_$now.sh

checkBadIPs_mail.sh

# One thing that is VERY important to note here is that you NEED to setup a whitelist or you are going to start blocking a lot of authentic IP’s from servers that you just receive a lot of email from or in the case of other logs, IP’s that just hit your server a lot for legitimate reasons.  My whitelist is just built into this screen by adding grep pipes  right after | grep ‘\]’ | that look something like this “grep -v 127.0 |”.  You need to take the time to teach your server which high traffic IP’s are legit and which aren’t, this just means you have to spend the first week or so checking your logs manually every couple of hours, looking up high traffic ip’s on iplocation.net and then adding the legit ones like amazon, box.com or even your home/office IP ranges to this whitelist.  If you don’t you will likely be blocked from your own server or you are going to start blocking legit mail servers and cause interruptions in email or traffic.

cat /var/log/mail.log | awk \
    -v d1="$(date --date="-2 min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -v 127.0 | \
    awk '{print $1}' | sort | uniq -c | sort -n | tail -10

BlockIP

#!/bin/bash
sudo iptables -I INPUT -s $1 -j DROP
sudo bash -c "iptables-save > /etc/network/iptables.save"

Again I know this is crude as hell and there is probably a nice clean efficient protocol that does all of this but I didn’t know about it and this thing has been going for a year or two now and keeping the bad guys at bay. The one thing I would very SERIOUSLY recommend is that you have a proxy or another server in the wings that you can use to access your main server.. The reason being is that if you are doing web development one day out of the blue and you ping your self 2000 times in 5 hours for some testing you could get blocked with no way back in except for a proxy.

You can see that in checkBadIPs.sh I’ve put grep -v 127.0 and in my actual files I have a ton of ignore rules for my own IP’s and other trusted IP ranges but sometimes your IP changes, you forget to update and then you’re locked out of your own server.

Anyways, hope that helps.

UPDATE

I have changed things a little bit so that now instead of checking every couple hours I have some logs checked every 2 minutes, mainly my ssh auth log and the mail log as they were getting pounded :(.

I setup specific scripts for each log file although it would be easy enough from the manual script I use myself when wanting to inspect logs click over here. Looks like this:

#!/bin/bash

log=$1 time=$2

cat /var/log/${log} | awk \
    -v d1="$(date --date="-${time} min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
    sort | uniq -c | sort -n | tail -10

This requires 2 inputs when run, the log file you want to scan and how far back into the past you want to scan.

So if I wanted to check mail.log for the ip counts say 75 minutes into the past I would run:

$ sudo script.sh mail.log 75
Tags: , , , , , , , , ,

One Comment to “Automatically block aggressive IPs to prevent brute force or DDOS attacks using Bash and IPtables”

  1. Dragonslayr says:

    Have you noticed, the script completely fails if time is past the rotation of the logs?

    ie script.sh mail.log 2400 returns nothing..
    Any thoughts?

    This was a perfect solution till I ran into that..

Leave a Comment