Misc:Abuse Log

From Amar
Jump to navigationJump to search
#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use DBI;
use Config::IniFiles;
use Net::Telnet;

$| = 1;

our $user	= 'admin';
our $pass	= 'xxxxxxxxx';
my $host1	= '192.168.20.1';
my $name1	= 'A';
my $host2	= '192.168.20.3';
my $name2	= 'B';
my $badip	= '';



# Requests of interest. Remember to do the regular expression
my $log_events	= { '.page'	=> 1,
				'.wmv'	=> 2,
				'.mov'	=> 2,
				'.cgi'	=> 3,
				'.pl'	=> 3,
				'.html'	=> 4,
			};
my $ids_events	= { '.jpg'	=> 5,
				'.bmp'	=> 5,
				'.png'	=> 5,
				'.gif'	=> 5,
			};
my $log_exts	= join("\|",keys(%$log_events));
$log_exts		=~ s/\./\\\./g;
my $log_ext_match	= qr/($log_exts)$/;
			
my $ids_exts	= join("\|",keys(%$ids_events));
$ids_exts		=~ s/\./\\\./g;
my $ids_ext_match	= qr/($ids_exts)$/;

my $dir_match	= qr{/};
			
my $max_hits	= { 1	=> 60,
					2	=> 12,
					3	=> 30,
					4	=> 120,
					5	=> 20,
				};

my $pattern	= qr/([0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+/;

# print Data::Dumper->Dump([$log_exts, $log_ext_match],[qw(log_exts log_ext_match)]);

my $exclude		= {};
&check_ip($exclude);

my $db	= 'ABUSE';
my $cfg	= Config::IniFiles->new( -file=> '/etc/db_connect.conf', -default=> 'DEFAULT');
my $dbi	= "DBI:mysql:".$cfg->val($db,"name").":".$cfg->val($db,"host");
my $dbh	= DBI->connect($dbi,$cfg->val($db,'user'),$cfg->val($db,'password'), {RaiseError => 1, AutoCommit => 0});
my $sth_ins	= $dbh->prepare(
				qq[INSERT INTO abuse_log 
					(IP,event_id,bucket_id,hits) 
					VALUES (?,?,MINUTE(NOW()),1)
				]);
my $sth_upd	= $dbh->prepare(
				qq[UPDATE abuse_log
					SET hits = hits + 1
					WHERE IP = ? AND event_id = ? AND bucket_id = MINUTE(NOW())
				]);
my $sth_get = $dbh->prepare(
				qq[ SELECT hits FROM abuse_log
					WHERE IP = ? AND event_id = ? AND bucket_id = MINUTE(NOW())
					
				]);

my $sth_log = $dbh->prepare(
				qq[ INSERT INTO blocked
					(IP,event_id,hits) 
					VALUES (?,?,?)
				]);

open ("STDOUT", ">>$ARGV[0]") || die $!;

while (my $line = <STDIN>) {
	chomp $line;
	my @fields = split /\|/, $line;
	my %fields = map { split /\=/,$_ } @fields;
	if ( $fields{U} =~ /$log_ext_match/ ) {
		# print STDOUT Data::Dumper->Dump([\%fields],[qw(*fields)]);
		my $event		= $1;
		my $ip			= $fields{I};
		my $subnet		= undef;
		if ($ip =~ $pattern) {
			$subnet	= $1;
		};
		if (exists($exclude->{$ip}) || exists($exclude->{$subnet})) {
			print STDOUT $line."\n";
			next;
		}
		my $event_id	= $log_events->{$event};
		my $max			= $max_hits->{$event_id};
		# Assume UPDATE and catch error
		eval{
			$sth_get->execute($ip,$event_id);
		};
		unless ($@) {
		my ($hits)	= $sth_get->fetchrow_array();
		$hits	||= 0;
		# print STDOUT Data::Dumper->Dump([$ip,$event,$event_id,$max,$hits],[qw(ip event event_id max hits)]);
		if ($hits > $max) {
			print STDOUT "***** ABUSE **** $ip $event ( $hits )\n";
			&disable_ip($ip);
			eval {
				open ABUSE_LOG, ">>/nfsroot/logs/log_abuse.log" or print STDOUT $!;
				print ABUSE_LOG "***** ABUSE **** $ip $event ( $hits )\n";
				print ABUSE_LOG Data::Dumper->Dump([\%fields, $hits, $max],[qw(*fields hits max)]);
				close ABUSE_LOG;
			};
			eval {
				$sth_log->execute($ip,$event_id,$hits);
			};
		}
		my $rv;
		eval{
			# print STDOUT "Updating";
			$rv = $sth_upd->execute($ip,$event_id);
			# print STDOUT "Error : '$@".$dbh->errstr."' rv = '$rv'\n";
		};
		if ($@ || $rv == 0) {
			eval{
				# print STDOUT "Inserting ";
				$sth_ins->execute($ip,$event_id);
			};
		}
		if ($@) {
			print STDOUT "BAD db: $@\n";
			$dbh->rollback();
		} else {
			$dbh->commit();
		}
		}
		print STDOUT $line."\n";
	} elsif ( $fields{U} =~ /$ids_ext_match/ ) {
		my $event		= $1;
		my $ip			= $fields{I};
		my $subnet		= undef;
		if ($ip =~ $pattern) {
			$subnet	= $1;
		};
		if (exists($exclude->{$ip}) || exists($exclude->{$subnet})) {
			print STDOUT $line."\n";
			next;
		}
		my $event_id	= $ids_events->{$event};
		my $max			= $max_hits->{$event_id};

		# IDS case #1
		# /home/www/v3/images/images/images/images/images/images/images/images/images/images ....
		# count the no of / and if above a #, kill the IP
		my @dirs		= split($dir_match, $fields{U});
		my $hits		= scalar(@dirs);
		
		
		# Log it
		if ($hits>$max) {
			print STDOUT "***** ABUSE **** $ip $event ( $hits )\n";
			&disable_ip( $ip);
			eval {
				open ABUSE_LOG, ">>/nfsroot/logs/log_abuse.log" or print STDOUT $!;
				print ABUSE_LOG "***** ABUSE **** $ip $event ( $hits )\n";
				print ABUSE_LOG Data::Dumper->Dump([\%fields, $hits, $max],[qw(*fields hits max)]);
				close ABUSE_LOG;
			};
			eval {
				$sth_log->execute($ip,$event_id,$hits);
			};
		}
	}

		# Temp LOG ALL - bad bad bad
		# print STDOUT $line."\n";
}

close (STDOUT);
$sth_log->finish;
$sth_ins->finish;
$sth_upd->finish;
$sth_get->finish;
$dbh->disconnect;

exit 0;

sub hold_it {

	my ($host,$name, @IPs)	= @_;

	my $session	= Net::Telnet->new (Timeout => 10, Prompt => '/.*#.*$/', Dump_log => '/tmp/telnet.log');
	# print "$host: @IPs\n";
	$session->open($host);
	$session->put($user."\n");
	$session->waitfor ('/.*Password:.*/');
	$session->put($pass."\n");
	# $session->login($user, $pass);
	#print $session->cmd(String => 'admin');

	# $session->waitfor('/ Name/');

	#$session->waitfor('/Password.*/');
	#print $session->cmd('g0dm0d3');
	$session->waitfor('/.*'.$name.'#.*/');
	my @output = $session->cmd('config t'."\n");
	my	$res	= join("\n",@output);
		$res	.= "\n";
	# $session->waitfor('/.*A\(config\)#.*/');
	



  # Execute a command
  # my @output = $session->cmd('show server real l83'."\n");
	# $session->waitfor('/.*\(config\)#.*/');
	foreach my $badip (@IPs) {
		$res	.= "$badip \n";
		@output = $session->cmd("security hold-source-ip $badip 60\n");
		$res	.= join("\n",@output);
		$res	.= "\n";
	}
	@output = $session->cmd('end');
		$res	.= join("\n",@output);
		$res	.= "\n";
	if (0) {
		@output = $session->cmd('exit');
		$res	.= join("\n",@output);
		$res	.= "\n";
		# $res .= $session->cmd('exit');
	}
	$session->close;

	print STDOUT $res;
};


sub disable_ip {

	my (@ips) = @_;
	&hold_it($host1,$name1,@ips);
	&hold_it($host2,$name2,@ips);

}

sub check_ip {
	my ($exclude)	= @_;
		my $ips = [qw( 
		195.92.67.71 
		166.102.104.65 
		24.191.101.131 
		211.50.250.249 
		152.163.207.214 
		213.154.134.157 
		68.47.133.228 
		63.118.66.11 
		166.102.104.65 
		206.154.135.67 
		208.236.105
		209.217.134.7 
		12.8.9.140 
		157.130.79.70 
		209.217.134.10 
		65.116.11.120 
		65.116.11.115
		4.36.232
		4.36.233
		4.36.234
		66.28.24
		208.62.228
		208.62.229
		208.62.230
		66.194.164.160 
		66.194.164.162
		66.194.164.157
		66.194.164.200
		69.25.84.2
		66.165.178
		65.223.64
		64.38.240
		64.38.241
		66.37.115
		64.74.164
		38.118.131
		)];
		
		%$exclude = map {$_ => 1 } @$ips;
}