Actually I was worried by the 404 error logs and the hell of 'File does not exist' log entries spewn by Apache on my server. I had done all sorts of hacks, like the one Redirect Worms Away by Richard Lowe, Jr. But it did not serve my purpose.
I was googling around and stumbled on How to Defeat Bad Web Robots With Apache By Lee Killough. I was impressed by the way he did using the apache module mod_rewrite. To make the story short.. I would say I followed his path till using the mod_rewrite, and deviated from there, and used a php/mysql combination to do the logging as well as blocking. Quoting Lee's words..
This one must be updated regularly, but here's a good place to start:
# Bad requests which have all been seen in real attacks
RewriteRule ^(/(scripts|msadc|MSADC|./winnt)|.*(default\.ida|[NX]{30}|c\+dir))
/cgi-bin/block.pl [L,T=application/x-httpd-cgi]
RewriteRule
^[^?]*/(owssvr|strmver|orders|Auth_data|redirect\.adp|MSOffice|DCShop|msadc|winnt|system32|script|autoexec|formmail\.pl|_mem_bin|NULL\.)
/cgi-bin/bad.pl [NC,L,T=application/x-httpd-cgi]
I changed this as follows, note that the block.pl is changed.. as well the application type too
RewriteRule ^(/(scripts|msadc|MSADC|./winnt)|.*(default\.ida|[NX]{30}|c\+dir))
/cgi-bin/block.php [L,T=application/x-httpd-php]
RewriteRule
^[^?]*/(owssvr|strmver|orders|Auth_data|redirect\.adp|MSOffice|DCShop|msadc|winnt|system32|script|autoexec|formmail\.pl|_mem_bin|NULL\.)
/cgi-bin/block.php [NC,L,T=application/x-httpd-php]
This catches the Code Red and Nimda worms. A shorter pattern could be used, but the pattern is flexible so that future variants will be caught as well. This catches many attempted exploits, like the formmail.pl exploit, which allows someone to anonymously send spam from the web server to anywhere they want, and the DCShop exploit, which allows collection of online shoppers' credit card data. I being more paranoid, changed his logger into blocker.
The following db structure was used to log the unwanted hosts
slno mediumint(8) PRIMARY KEY AUTO_INCREMENT ipaddr varchar(20) entry datetime blocked smallint(0) unsigned default '0'
The following php code compliments the mod_rewrite
<?
$addr = $REMOTE_ADDR;
$db="database";
$db_host="localhost";
$db_user="dbu";
$db_pwd="dbp";
$link = mysql_connect($db_host, $db_user, $db_pwd) or die("Couldnot
connect to mysql");
mysql_select_db($db) or die("Could
not select database");
$query = "update blockhosts set entry = now() where ipaddr = '$addr'";
$result = mysql_query($query);
if(mysql_affected_rows() ==
0){
$query
= "insert into blockhosts
(ipaddr,entry) values ('$addr',now())";
$result
= mysql_query($query);
}
header("Status: 403 Forbidden");
print "
<html><head><title>403
Forbidden</title></head><body>
<h1>403 Forbidden</h1>
You don't have permission to access $url on this server.
</body></html>
";
?>
The following php code does the real blocking using ipchains.. it also removes the blocks after some time
<?php
//this is to be run as a cron job. every hour
//8 * * * * /usr/bin/php -q [full path to script]
$b_delay = "60 minute"; //
hosts logged in the last 1 hour will be blocked
$r_delay = "60 minute"; //
hosts blocked for more than 1 hour will be released
$db="database";
$db_host="localhost";
$db_user="dbu";
$db_pwd="dbp";
$link = mysql_connect($db_host, $db_user, $db_pwd) or die("Couldnot
connect to mysql");
mysql_select_db($db) or die("Could
not select database");
$query = "select slno,ipaddr from blockhosts where blocked=1 and entry <
date_sub(now(),interval $r_delay) order by slno";
$result = mysql_query($query) or die(mysql_error());
while($line = mysql_fetch_row($result)){
exec("/sbin/ipchains -D input -s $line[1]/32 -d 0/0 -j
DENY");
$squery
= "update blockhosts set blocked=0
where slno=$line[0]";
$sresult
= mysql_query($squery);
}
$query = "select slno,ipaddr from blockhosts where blocked=0 and entry >
date_sub(now(),interval $b_delay) order by slno";
$result = mysql_query($query);
while($line = mysql_fetch_row($result)){
exec("/sbin/ipchains -A input -s $line[1]/32 -d 0/0 -j
DENY");
$squery
= "update blockhosts set
blocked=1,entry=now() where slno=$line[0]";
$sresult
= mysql_query($squery);
}
?>
This has nothing to do with a comparison.. I would recommend Lee's solution,
but for me it was just a gap between knowing and not knowing.. I know php much better than
perl.. hence I thought employing the mysql part would reduce the system load a little bit..
thats all..
© 2003 Saturn InfoLab http://www.saturn.in