howto block w00tw00t.isc.sans.dfind:) und andere scans mit iptables

In letzter Zeit sind mir in meinen webserverlogs vermehrt scans von scripten nach bestimmten Pfaden bzw. nicht geschlossene Verbindungen die von user agents stammten die den string „w00tw00t.isc.sans.Dfind:)“ und Variationen davon beeinhalteten aufgefallen. Diese stammten teilweise von Dialup ipadressen aber auch von vermutlich geknackten webservern mit festen ipadressen. Um dem ganzen Einhalt zu gebieten habe ich ein shellscript geschrieben, das die webserverlogs nach bestimmten strings absucht und die dazugehoerigen IP-adressen sperrt. Das script setzt voraus, das keinerlei Installationen von z.B. phpmyadmin oder anderer Verwaltungssoftware in standardpfaden existiert. Diese sollte ein verantwortungsvoller Admin auf öffentlichen Produktionsservern sowieso nicht verwenden 😉

Eine zeitabhängige Variante ist noch in Arbeit, leider fehlt mir dafür momentan die Zeit. Ich empfehle doppeltes und dreifaches testen bevor das ganze mit einem cronjob automatisiert wird.

Wenn die Befehle unterhalb der

###debug###

Statements einkommentiert werden kann das ganze getestet werden. Zum testen sollten auch die „scharfen“

iptables Zeilen wie folgt auskommentiert werden:


#${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;

Am Anfang der root crontab sollten folgende Zeilen stehen damit iptables gefunden wird und eventuelle Fehler per email gesendet werden.


MAILTO='someaddress@somedomain.com'
PATH=/usr/sbin:/usr/bin:/sbin:/bin

ich empfehle SEHR das whitelisting von anderen servern oder der momentan verwendeten ip
-> waehrend des testens habe ich auch aus Versehen meine eigene zu dem Zeitpunkt aktuelle dynamische ipadresse gesperrt 🙁

Und wie immer gilt: Benutzung auf eigene Gefahr + Erst DENKEN/verstehen und dann implementieren.

Hier nun das 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;

 

Das ganze ersetzt natürlich keine apache modsecurity application firewall sondern ist ein eher krudes shellscript.

so long
Arnd