Lately I recognized the increase of scans for some certain paths resp. not closed connections from user agents containing strings like “w00t.isc.sans.Dfind:)” and variations thereof. The source of these strings were from dialup ip adresses but also from some probably hacked fixed server ip adresses. To get rid of these scans I whipped up a shellscript which scans the apachelogs and utilizes iptables to block these ip adresses. The script assumes there are no installations of phpmyadmin or other server management software in a standard path. A responsible acting admin should’t use this kind of thing on openly accessible production servers anyway methinks 😉
A timedriven version is in the works, but I’m lacking the time to implement this ATM.
A useful debug output should be generated if one comments in the part below the
###debug###
staments.
I strongly recommend to start some dryruns before implementing it via cronjob and to comment out the HOT part like this:
#${IPTABLESPATH} -I INPUT -s "$ip" -j LOG --log-level 4 --log-prefix '** HACKERS **';
#${IPTABLESPATH} -I INPUT -s "$ip" -j DROP;
#${IPTABLESPATH} -I OUTPUT -s "$ip" -j DROP;
One should put
MAILTO='someaddress@somedomain.com'
PATH=/usr/sbin:/usr/bin:/sbin:/bin
on top of root’s crontab so that iptables is found via the “which” statement and one gets errors via email.
I recommend to put ip’s of other servers or Ur current ip in the whitelist “if statement”
-> got some headaches when /me locked out my then dialup ip of netzturbine while testing 🙁
And as always: Use at your own risk + THINK/understand 1st what this is about and THEN implement it.
nuff said – here is the script.
#! /bin/bash
############################################################################################################################
# badstrings ban script
# version 0.3beta
# by arnd@netzturbine.de (https://identi.ca/netzturbine) and THEOTHERGUYOFNETZTURBINE
# parses the apache logs for banstrings and greps latest attacker ips from accesslogs and errorlogs
# loads list w/o doubles into iptables
# a time releveant component needs to be implemented
# !!!Handle w/ care whitelisting of ip’s is very necessary (i.e another server to keep access if locked out from own ip)!!!
############################################################################################################################
#devel path
#cd ~/Documents/devel/ip_blocker/;
#use on live systems directory must exist and contain this script
cd /root/bin/ip_block/;
###debug####
#pwd;
#set system type
#could be suse or non-suse
#if suse use SuSEfirewall2 scripts on top of this
system=”suse”
#check if iptables is installed and found otherwise exit
IPTABLESPATH=$(which iptables);
if [ $? == “1” ]
then
echo “iptables not found”;
exit;
fi
#set logformat
# if it is vhost 2nd ip ist to block if it is common 1st ip is to block
# check log_format.conf for possible values
# check somevhost.conf for used format
LOGFORMAT=”vhost”
#set logpath
LOGPATH=”/var/log/apache2/”;
#Declare accesslogs array
#if multiple accesslogs are used put them with blanks like
# ACCESSLOGS=( ${LOGPATH}access_log ${LOGPATH}other_access_log);
ACCESSLOGS=( ${LOGPATH}access_log;
#Declare errorlogs array
#if multiple errorlogs are used put them with blanks
ERRORLOGS=( ${LOGPATH}error_log );
#declare banstringsarray
#be careful all requests containing these strings !!!case insensitive!!! AND throwing error 404 in access logs or showing up in error log are blocked except whitelisted ip’s
BANSTRINGS=( ‘w00t’ ‘phpmy’ ‘mysql’ ‘script’ ‘attacker’ );
#resetting logs
# no better way to keep bans low until timestamps are implemented
# bears risk of being scanned by same host again
# comment in if users are mostly on dialup hosts
# logrotate should be on daily basis
#rm ./ban*;
# get number of elements in arrays
ACCESSLOGSNUMBER=${#ACCESSLOGS[@]}
###debug####
#echo “ACCESSLOGSNUMBER: ${ACCESSLOGSNUMBER}”;
ERRORLOGSNUMBER=${#ERRORLOGS[@]}
###debug####
#echo “ERRORLOGSNUMBER: ${ERRORLOGSNUMBER}”;
BANSTRINGSNUMBER=${#BANSTRINGS[@]}
###debug####
#echo “BANSTRINGSNUMBER: ${BANSTRINGSNUMBER}”;
#parsing access logs looking for 404 errors and ${BANSTRINGS} to keep correct requests
i=0;
# outer loop through logs
while [ ${i} -lt ${ACCESSLOGSNUMBER} ]
do
###debug####
#echo “parsing log: “${ACCESSLOGS[${i}]};
#inner loop through banstrings
j=0;
while [ ${j} -lt ${BANSTRINGSNUMBER} ]
do
###debug####
#echo “No ${j} string to ban: ${BANSTRINGS[${j}]}”;
#if logformat is vhost 2nd ip is attacker
if [ “${LOGFORMAT}” == “vhost” ]
then
#creating list – printing 2nd column – logformmat vhost – sorting w/ uniqueness
less ${ACCESSLOGS[${i}]} | grep 404 | grep -i ${BANSTRINGS[${j}]}.* | awk ‘{ print $2 ‘} | sort -u >> ./ban_latest_list;
else
#creating list – printing 1st column – Log format common – sorting w/ uniqueness
less ${ACCESSLOGS[${i}]} | grep 404 | grep -i ${BANSTRINGS[${j}]}.* | awk ‘{ print $1 ‘} | sort -u >> ./ban_latest_list;
fi
j=$[${j}+1];
done
#increment
i=$[${i}+1];
done
#parsing error logs
#creating list from error logs
i=0;
# outer loop through logs
while [ ${i} -lt ${ERRORLOGSNUMBER} ]
do
###debug####
#echo “parsing log: “${ERRORLOGS[${i}]};
#inner loop through banstrings
j=0;
while [ ${j} -lt ${BANSTRINGSNUMBER} ]
do
less ${ERRORLOGS[${i}]} | grep -i ${BANSTRINGS[${j}]}.* | awk ‘{ print $8 ‘} | sort -u | sed ‘s/]//g’ >> ./ban_latest_list;
j=$[${j}+1];
done
#increment
i=$[${i}+1];
done
#merge lists
less ./ban_latest_list > ./ban_tmp_list;
less ./ban_list >> ./ban_tmp_list;
#create final list keep ip’s unique
less ./ban_tmp_list | sort -u > ./ban_list_unique;
#remove empty lines
sed ‘/^$/d’ ./ban_list_unique > ./ban_list;
#flushing firewall
if [ “${system}” == “suse” ]
then
###debug####
#echo “suse”;
/sbin/SuSEfirewall2 stop 2>&1 > /dev/null;
/sbin/SuSEfirewall2 start 2>&1 > /dev/null;
else
###debug####
#echo “non-suse”;
${IPTABLESPATH} -F;
${IPTABLESPATH} -X;
${IPTABLESPATH} -t nat -F;
${IPTABLESPATH} -t nat -X;
${IPTABLESPATH} -t mangle -F;
${IPTABLESPATH} -t mangle -X;
${IPTABLESPATH} -P INPUT ACCEPT;
${IPTABLESPATH} -P FORWARD ACCEPT;
${IPTABLESPATH} -P OUTPUT ACCEPT;
fi
#load list of blocked ip’s
for ip in $(< ./ban_list);
do
#keep whitelisted hosts even if they give a false error + filter some strings falsely returned like “-” OR “PHP”
#ip’s put in if statement are NOT blocked whatever happens
if [ “${ip}” == “” ] || [ “${ip}” == “” ] || [ “${ip}” == “” ] \
|| [ “${ip}” == “-” ] || [ “${ip}” == “PHP” ] || [ “${ip}” == “file” ]
then
###debug####
#echo “${ip} whitelisted – do nothing”;
continue;
else
###debug####
#echo “need to block attacker ${ip}”;
${IPTABLESPATH} -I INPUT -s “$ip” -j LOG –log-level 4 –log-prefix ‘** HACKERS **’;
${IPTABLESPATH} -I INPUT -s “$ip” -j DROP;
${IPTABLESPATH} -I OUTPUT -s “$ip” -j DROP;
fi
done
###debug####
#less ./ban_list;
The whole thingy does not substitute an apache modescurity application firewall but is more a crude implementation.
So long
Arnd