[ale] $#@% bugged M$ web bashers!

James P. Kinney III jkinney at localnetsolutions.com
Wed Nov 7 23:28:51 EST 2001


I got pounded lately from the lusers who have been infected with the
latest round of M$ web-server bug. 

So I hacked up a script that gets their IP from the apache error_log(s)
and bans them from my server at the firewall. The strings to search for
are configurable near the top. It won't prevent them from wasting my
bandwidth. But it will stop them from wasting my server cpu time.

That felt good! So I thought I'd share the code. I even put in a few
comments. I run it with no args every few minutes to quickly blacklist a
box. Cron runs it with the daily log rotate process. There is some aging
built in to get the IP's off the list as the logs roll out. Most of the
lusers are on dhcp and shouldn't have their IP permanently banned from
the site. Or maybe they should...

Any rate, hope it's useful.
-- 
James P. Kinney III   \Changing the mobile computing world/
President and COO      \          one Linux user         /
Local Net Solutions,LLC \           at a time.          /
770-493-8244             \.___________________________./

GPG ID: 829C6CA7 James P. Kinney III (M.S. Physics)
<jkinney at localnetsolutions.com>
Fingerprint = 3C9E 6366 54FC A3FE BA4D 0659 6190 ADC3 829C 6CA7 




#!/usr/bin/perl
# This is for extracting the Micro$oft boxes that have been compromised
# and blocking their access to the webserver
use strict;

# the file with the data is 
my $log = "/var/log/httpd/error_log";

# old log files add a .i i=1..4

# the place to store the output IP's to block
my $dropfile = "/etc/hosts.web.deny";

# strings to search for in the log file
my @strings = ("winnt", "cmd.exe", "root.exe");

# create a hash of the already blocked IP's

my ($key, %dropped, %filed, %block_these, %blocked, $in, @IN, $logfile, $j);

# Accept args to search all log files
my $log_depth = "0";
my $all = $ARGV[0];
#print "arg = $all\n";
if ($all =~ m/\w/){$log_depth = "4"}

%filed = get_filed_hosts();

%block_these = get_hosts_to_block();

%dropped = iptables_firewall_check();

if ($log_depth == 4){
	foreach $key (keys %filed){ # removes old IP's from blacklist
		if ($block_these{$key} !~ "drop"){delete $filed{$key}}
	}
	write_drop_file();
}
else{ # Should handle a restart OK
	foreach $key (keys %filed){ # add all filed IP for blocking.
		if ($block_these{$key} !~ "drop"){$block_these{$key} = "drop"}
	}
	write_drop_file();
}

foreach $key (keys %dropped){
        delete $block_these{$key} #no duplicate filter rules
}

# Do the deed
foreach $key (keys %block_these){
	if ($key =~ m/\d+\.\d+\.\d+\.\d+/){
		`/sbin/iptables -I INPUT -s $key -j DROP`;
	}
}

#################################
##   Subroutines
#################################

sub get_filed_hosts{
	# create a hash of the already blocked IP's
	open (IN, "<$dropfile") || die "Failed to open $dropfile for read\n";
	@IN = <IN>;
	close IN;
	chomp(@IN);
	foreach $in (@IN) {
 	       $filed{$in}="filed";
	}
}

sub write_drop_file{
        my $key;
        open (OUT, ">$dropfile") || die "failed to open $dropfile for write\n";
        foreach $key ( keys %blocked ){
                if ($key =~ m/\d+\.\d+\.\d+\.\d+/){
                        print OUT "$key\n";
                }
        }
        close OUT;
}

sub get_hosts_to_block { # generate list of IP's to block from httpd log files
	# open logfile and stuff into an array for string searching
	my (@temp, $match, $i, %block_these);
	for ($j=0; $j<=$log_depth; $j++){
        	if ($j == 0){$logfile=$log}
        	else {$logfile = $log.".$j"}
		if ( -r $logfile){
			open (IN, "<$logfile") || die "failed to open $logfile for read\n";
			@IN=<IN>;
			chomp(@IN);
			close IN;
		}
		for ($i=0;$i<=$#strings;$i++){
			$match .= $strings[$i];
			if ($i != $#strings) {$match .= "|"}
		}	
		foreach $in (@IN){
			if ($in =~ m/$match/){
				@temp = split( /\s/, $in);
				# $temp[8] has ip address pluss and extra "]" on the end.
				chop($temp['8']);
				$block_these{$temp['8']} = "drop";
			}
		}
	}
	return %block_these;
} #end sub host_block		

sub iptables_firewall_check { #get list of IP's currently blocked
	my (@rules, %temp, @dropped, $IP);
	@rules = `/sbin/iptables -L INPUT -n | grep DROP | grep -v INPUT`;
	chomp(@rules);
	my (@temp);
	foreach my $rule (@rules){
		#print "$rule\n";
		@temp = split (/\s+/, $rule);
		#print "IP=$temp[3]\n";
		if ($temp[3] =~ m/\d+\.\d+\.\d+\.\d+/){
			push (@dropped, $temp[3]);
		}
	}
	foreach $IP (@dropped){
		#print "dropped IP -> $IP\n";
		$temp{$IP} = "FW";
	}
	return %temp;
}



---
This message has been sent through the ALE general discussion list.
See http://www.ale.org/mailing-lists.shtml for more info. Problems should be 
sent to listmaster at ale dot org.




More information about the Ale mailing list