#!/usr/bin/perl # # bigfish.pl # A Program to look for big fish in your LaBrea Tarpit and send you notification # Adapted from LaBrea::Tarpit::Report which is # Copyright 2002, 2003, Michael Robinton & BizSystems # This has been modified under the terms of GNU GPL license on 25SEP04 # No rights reserved under this modification # See additional documentation for this program at: # http://www.pettingers.org/code/bigfish.html # # This program is useless unless you are running # Michael Robinton's LaBrea::Tarpit program # (available from CPAN) # # my $version = '1.0'; # # use strict; use LaBrea::Tarpit qw( prep_report restore_tarpit ); use LaBrea::Tarpit::Report qw( guests_by_IP ); use LaBrea::Tarpit::Util qw( daemon2_cache page_is_current ); use MIME::Lite; ######################################################### ######## CONFIRM THE CONFIGURATION BELOW ############### ######################################################### use lib qw( ./ ); # SET for your system # my $config = { 'd_host' => 'localhost', # defaults to 'localhost' 'cache' => '/var/tmp/labrea.cache', 'scanners' => 100, # keep this many dead threads 'port_intvls' => 30, # keep #nintvls of port stats }; # SET THESE for your system my $look_n_feel = { # defaults shown 'face' => 'VERDANA,ARIAL,HELVETICA,SANS-SERIF', 'color' => '#ffffcc', 'bakgnd' => '#000000', # below are all for port_intervals 'images' => '/icons/', # REQUIRED, path to images 'threshold' => 10, # ignore below this count 'html_cache_file' => '/var/tmp/bigfish.cache', # required 'html_expire' => 60, # cache expiration, secs # optional other_sites stats cache location }; my (@thsip,@thnum,@orgdata); ####### Set the threshold for LARTing here. Minimum number of sustained sockets before LART is generated. my $isbigfish = 200; ####### my ($fish, $lart, $lline, $mails, $msg, $lartaddr) = ''; ####### Set keys to look for in whois data. The items below generally do fairly well but could be fine-tuned. my $abuseinfo = "e-mail|abuseemail|OrgAbuseEmail|OrgTechEmail|TechEmail|abuse\@"; ####### ####### This is the file that will store a list of fish so you don't get repeated alerts on the same one. ## You can clear this out daily or weekly with a cron job. my $fishfile = "/var/tmp/fishfile.cache"; ####### # ## END OF USER CONFIGURATION ############################################## # ####### ############ -- Generate a fresh cache of the tarpit before we go fishing -- ############ my ($image_cache,$use_cache,$error,$rpt,$sht,$html,$report,$short,$out,%tarpit); my $page = 'attackers'; my ($mtime,$upd); # first thing, check the cache age ($mtime,$upd) = daemon2_cache( $look_n_feel->{html_cache_file}.'.mem', $config, $look_n_feel->{html_expire}, ); $error = $@; if ($error) { # was there a timeout error $page = 'error'; # falls through elsif's # note that $upd & $use_cache will be false } # else { restore_tarpit(\%tarpit,$look_n_feel->{html_cache_file}.'.mem') unless ($use_cache = page_is_current($mtime, # always set $use_cache $look_n_feel->{html_cache_file}.'.'.$page)) || $page eq 'other'; # but skip restore if tarpit not needed # } ############## -- START of fishing -- ################ $out = { # threads per tarpitted host 'guests_by_IP' => undef, 'th_srcIP' => \@thsip, 'th_numTH' => \@thnum, # number threads this IP }; prep_report(\%tarpit,$out); guests_by_IP($out,$look_n_feel,$out); $rpt = \$out->{guests_by_IP}; ####### Dig through generated report looking for BigFish for ($fish=0; $fish < (scalar(@thsip)); $fish++) { if ($thnum[$fish] >= $isbigfish){ ####### Got one! Do an abuse desk lookup $lart = getwhois($thsip[$fish]); @orgdata = split(/:/, $lart); $lart = ''; $mails = "\n\n\n"; $lline = shift(@orgdata); while ($lline) { if ($lline =~ m/$abuseinfo/i){ $lline = shift(@orgdata) unless ($lline =~ m/abuse\@/i); $lline = substr($lline, 0, (index($lline, "\n"))); $lline =~ s/\s//g; # print "abuse info is: $lline\n"; ####### Delete the following line if you are going to LART directly. What this does is embed the abuse ## E-mail addresses into the body of the message which will be sent to you. You can then cut-and-paste ## these addresses into the TO: line of a LART from another account if you wish. If you want to LART ## directly, delete this and look below for other comments about what to change in the MIME::Lite ## generated message. ######## $mails .= "$lline\; "; ######## $lartaddr .= "$lline\; "; } $lline = shift(@orgdata); } # print "Big Fish! Address = $thsip[$fish] with $thnum[$fish] sockets at position $fish \n"; $mails = substr($mails, 0 , -2); ####### This is the actual text of the message that will be generated. Could be coded a bit more elegantly.... $mails .= "\n\n\n\n\nYour host with IP address $thsip[$fish] is attacking our site.\n\n This attack may simply be the result of an infected Microsoft Windows host attempting to propagate a virus/worm or may be a directed, intentional attack. There are currently $thnum[$fish] malicious sockets connected to our server. Please disconnect this host from the network IMMEDIATELY. Your netblock has been BLACKLISTED until this issue is resolved.\n If you would like to speak to our technical support department regarding this matter, please call\: 1-123-555-1234 x-1234\n\n Please note: This message is sent from a filtered account. However, it is monitored for replies. Thank you for your prompt action in resolving this issue."; ####### Note that the message below will print out to STDOUT even if an E-mail is not sent. ## That is, the message will print for debugging purposes even though the host ## may be in the fishfile.cache (i.e. already LARTed) ####### print "\n++++++++++++++++++++++++\n Message is--\n\n $mails \n+++++++++++++++++++++++++\n"; ####### Check the list of previous fish to see if we have already sent a LART for them. $lart = ''; open (PTR, $fishfile) || die ("Could not open file. \n $!"); $lline = ; while ($lline){ if ($lline =~ m/$thsip[$fish]/) { $lart = 1; } $lline = ; } close (PTR); ####### Unless we already sent something, send a message out using MIME::Lite ## NOTE: As it stands now, it will send this message to you as (presumably) system administrator. ## Obviously you could have it send it to whomever you like, but if you want to have ## it sent directly to the offending ISP/organization abuse desk, you'll need to make ## the following modification: ## To =>$lartaddr, ## instead of the current: ## To =>'admin@mydomain.org', ####### unless ($lart) { # Format the message to send with MIME::Lite package $msg = MIME::Lite->new( From =>'Security@mydomain.org', To =>'admin@mydomain.org', Bcc =>'abuse@mydomain.org', Subject =>"Malicious Activity From Your Network -- $thsip[$fish]", Data =>$mails ); # Send it best way possible (usually sendmail) $msg->send; ####### They've been LARTed. Put them in the fish file open (PTR, ">>$fishfile")|| die ("Could not open file. \n $!"); print PTR "$thsip[$fish]\n"; close (PTR); } $mails = ''; } # end if > big fish } # end for ########################################################################################## sub getwhois { BEGIN { use vars qw($old_d_q $lastresp); use Net::Whois::IP qw(whoisip_query); $old_d_q = \&Net::Whois::IP::_do_query; } sub Net::Whois::IP::_do_query { my @rv = &$old_d_q(@_); $lastresp = $rv[0]; return @rv; } ######################################################### $ENV{SCRIPT_NAME} =~ /whois\.([a-zA-Z_-]+)/; my $action = 'whois.'. $1; my $IP = "@_"; #my $IP = ($ENV{QUERY_STRING} =~ /query=(\d+\.\d+\.\d+\.\d+)/) # ? $1 : ''; my $html = ''; if ($IP) { $lastresp = ''; eval {whoisip_query($IP)}; if ($lastresp && ! $@) { $html .= join('',@$lastresp); } else { $html .= 'could not connect to whois server, try again later'; } } # print "your info--- $html\n---\n"; return $html; } # end of subroutine exit; ##############