#!/usr/bin/perl ########################################################################### # # 6/1/2004 Author: Joe Barbish, I bequeath this perl script to public domain. # It can be copied and distributed for free by anyone to anyone by any manner. # # This script first executes the abuse.public.ISP1.pl script. It reads the # ipf log, drops log records based on the exclusion file, and creates an file # that is sorted into source IP address sequence, # performs an whoi command to harvest the abuse reporting email address of # the ISP who owns the IP address range and then creates an email containing # all the log records for that offending source IP address which is then # sent to the owning ISP reporting the probing abuse. The exclusion file # contains only the IP address ranges used on your private LAN if you have # any and the IP address range owned by your ISP. # # An single email per each abusing source IP address containing it's log # records is sent. This generates a lot of email. 99% of the abusive source # IP address resolve to good owner ISP abuse reporting email address. # RIPE and APNIC have merged their data into the whois.internic.org # database which makes this possible. There are still some South America # countries which have not as yet merged their data. # ########################################################################### use Getopt::Std; getopts("l:v:"); $verbose = 0; $build_email = "yes"; # define default email address. (don't forget backslash before @) # Sender email address #$email_from="root\@this.machine"; # The To email address to send your ipfilter converted log records # to as content in the body of the email. # Testing send it to your self so you can verify things are working. #$email_to="root\@this.machine.com"; # The CC email address # Send copy of email to your self to verify and track regular submision. #$email_cc="root\@this.machine"; #$email_cc=""; if ($opt_v ne "") { $verbose=$opt_v; } if ($verbose eq "1") { # enable debug statements buried in logic # and display email instead of sending to sendmail $build_email = "no"; } if ($verbose eq "2") { # enable debug statements buried in logic # and send email to self $build_email = "yes"; $email_from="dshield\@this.machine.com"; $email_to="joe\@this.machine.com"; $email_cc=""; } if ($verbose eq "3") { # disable debug statements buried in logic # and send email to self $build_email = "yes"; $email_from="dshield\@this.machine.com"; $email_to="joe\@this.machine.com"; $email_cc=""; } # Run script to read /var/log/security.0 and create # /var/log/abuse.public.ip.file which is in DShield record layout # with ip address padded with zeros so they will sort correctly. system("/root/bin/abuse.public.ISP1.pl -l /var/log/security.0"); # sort on source ip address, date, time system("sort -b -k 4.1,4.15 -k 1.1,1.10 -k 2.1,2.8 < /var/log/abuse.public.ISP1.file > /var/log/abuse.public.ISP1.sorted.file"); # init some control fields $prev_sip=""; $sip=""; $sendmail="/usr/sbin/sendmail"; $email = ""; $runlog = "/var/log/abuse.public.ISP0.runlog"; # open run log file to record IP address & whois found abuse email addr open(OUT_log,">$runlog"); debug("Start processing sorted file\n"); open(IN1,"/var/log/abuse.public.ISP1.sorted.file"); while ($line1=) { chop($line1); @f=split(/\s+/,$line1); debug(" \n"); debug("process i/p record loop\n"); debug("line = $line1\n"); $sip=$f[3]; debug("sip = $sip\n"); if ($sip ne $prev_sip) { debug("New sip ne prev_sip\n"); if ($email ne "") { debug("New sip & prev_sip had abuse email address = $email\n"); $prev_sip=$sip; $email = ""; #close email so it will send close(OUT); $email_sent_count++; $do_whois="yes"; } else { debug("New sip & prev_sip had no abuse email address\n"); $do_whois="yes"; } } else { debug("Dup New sip = prev_sip\n"); if ($email ne "") { debug("dup sip & prev_sip had abuse email address\n"); # write line to email print(OUT "$line1\n"); $do_whois="no"; } else { debug("Dup sip & prev_sip had no abuse email address\n"); debug("line = $line1\n"); $do_whois="no"; } } if ($do_whois eq "yes") { debug(" \n"); debug("start do_whois routine on $sip\n"); $email=do_whois("$sip"); debug("returned email address = $email\n"); $prev_sip=$sip; # IP address not officially in use. if (($email eq "No match found") || ($email eq "No match found -a or -r") || # official whois info has No contact email ($email eq "No contact email -a or -r") || ($email eq "No contact email")) { debug("main IP & email address = $sip\t$email\n"); print(OUT_log "$sip\t$email\n"); $email = ""; } if ($email ne "") { debug("Sub whois found abuse email address = $email\n"); debug("main IP & email address = $sip\t$email\n"); print(OUT_log "$sip\t$email\n"); # Prepare sendmail debug("Piping to sendmail\n"); # $build_email = "yes"; # $build_email = "no"; if ($build_email eq "no") { open(OUT,"| /bin/cat") || die "Cant open sendmail pipe"; debug("open cat\n"); } else { open(OUT,"| $sendmail -t -oi") || die "Cant open sendmail pipe"; debug("open sendmail\n"); } print(OUT "From: $email_from\n"); if (($verbose eq "2") | ($verbose eq "3")) { print(OUT "To: $email_to\n"); } else { print(OUT "To: $email\n"); } print(OUT "Cc: $email_cc\n"); print(OUT "Subject: $sip Abuse report.\n\n"); print(OUT "This report is created from firewall logs of blocked\n"); print(OUT "unsolicited inbound packets originating from one of your customers.\n"); print(OUT "Your customer is probing an subnet block of IP address searching\n"); print(OUT "for specific open port numbers. This is abusive behavior.\n"); print(OUT "This is bandwidth abuse that I get charged an bandwidth usage\n"); print(OUT "surcharge for. Your customer is stealing money from me in\n"); print(OUT "increased bandwidth charges.\n\n"); print(OUT "The email address this email is sent to was auto harvested\n"); print(OUT "from whois databases. If it is incorrect, then please\n"); print(OUT "update your entry in your register's whois database with an handle\n"); print(OUT "containing the international standard naming convention\n"); print(OUT "of abuse\@your_domain (all lower case & surrounded by white space)\n"); print(OUT "as the official email address to report abuse to.\n\n"); print(OUT "The entry should look like this.\n"); print(OUT "AbuseEmail: abuse\@your_domain.tld\n\n"); print(OUT "Report format contains the following items in this order\n"); print(OUT "1. Date and Time as YYYY-MM-DD HH:MM:SS of abuse access attempt:\n"); print(OUT "2. tzHH:tzMM). timezone offset from GMT:\n"); print(OUT "3. source IP address:\n"); print(OUT "4. source port:\n"); print(OUT "5. target IP address:\n"); print(OUT "6. target port:\n"); print(OUT "7. protocol (text like 'TCP','UDP'...):\n"); print(OUT "8. TCP flags (S-SYN, A-ACK, F-FIN, U-URG, R-RST, P-PSH):\n"); print(OUT " \n"); print(OUT "$line1\n"); } else { debug("dowhois New sip no abuse email address\n"); debug("line = $line1\n"); } } } debug("EOF sorted file\n"); close(IN1); # close sorted in close(OUT_log); # close saved record file without whois found email addr if ($email ne "") { # close email so it will send close(OUT); $email_sent_count++; } # Create run history file $run_date = localtime; open(run_history,">> /var/log/abuse.public.ISP0.run.history"); print (run_history "$run_date Emails sent = $email_sent_count\n"); close(run_history); exit 0; sub do_whois # Given an IP address issues "whois" and searches for the owners email address # to report abuse to. Some conditions exist where based on the findings of # the whois output an second whois must be issued to drill deeper into # different whois database structures to finally harvest the owners # email address. { $sub_sip=@_[0]; # name ip address passed to subroutine $email=""; $whois_arg = ""; $net_block = ""; $abuse_email = ""; $err_msg = ""; # | means pipe o/p to if (open(WHOIS, "(whois $sub_sip) |")) { # this executes the whois cmd and pipes the output to an in core file debug("doing harvest whois o/p for abuse email addr logic\n"); # the following while loop reads each line of the whois o/p while () { debug("while whois loop1\n"); debug("line = $_\n"); # $_ contains 1 o/p line from whois cmd $line = $_; debug("line= $line\n"); # look for invalid IP, whois returns 'No match found'. if (/No match found for/) { $email = "No match found"; last; } # The whois command defaults to using the whois.internic.net database. # This global database will automatically do lookup in ARIN & APNIC & # LACNIC & RIPE whois databases. # ID and setup special JPNIC whois call. # The JPNIC is in Japanese, add /e suffix to end of IP for English version. if (/Japan Network Information Center/) { $whois_arg = "-c jp"; $english = "/e"; $sub_sip = "$sip$english"; debug("JPNIC found, ip = $sub_sip\n"); last; } # ID and setup special Brazil whois call. if (/have been further assigned to Brazilian users/) { $whois_arg = "-c br"; debug("Brazilian IP found, ip = $sub_sip\n"); last; } # Some large USA ISP's just have net ip address block records in the # whois.internic.net global whois database that have no contact info. # An special whois -a call must be issued to get detailed info from # ARIN whois database. # ID and setup special ARIN whois call. (NET-205-148-208-0-1) if (/(NET-\d{1,3}-\d{1,3}-\d{1,3}-0-1)/) { $net_block = ${1}; debug("found net_block = $net_block\n"); } # parse into fields surrounded by blanks @f=split(/\s+/,$line); # look for special abuse@ email address in body of whois o/p # some ISPs do not use the standard handle to define abuse@ email address # if found this superseads all other found contact email address debug("Scan line for word abuse, line= $line\n"); if ((/(abuse\@[a-zA-Z0-9\.\-\_]+)/) || (/(anti-spam\@[a-zA-Z0-9\.\-\_]+)/)) { if ((${1} =~ /\@apnic.net/i) || (${1} =~ /\@lacnic.net/i)) { next; } else { $abuse_email = ${1}; debug("abuse_email body = $abuse_email\n"); } } if (($f[0] eq "AbuseEmail:") || ($f[0] eq "OrgAbuseEmail:")) { $abuse_email = $f[1]; debug("abuse_email handle= $abuse_email\n"); } if (($f[0] eq "e-mail:") || ($f[0] eq "notify:") || ($f[0] eq "OrgNOCEmail:") || ($f[0] eq "OrgTechEmail:") || ($f[0] eq "TechEmail:")) { debug("found email handle = $f[0]\n"); if (($f[1] =~ /\@apnic.net/i) || ($f[1] =~ /\@lacnic.net/i)) { next; } else { debug("found email label = $f[0]\n"); $email = $f[1]; if ($f[1] =~ /\@telefonica.es/i) { $email = "nemesys\@telefonica.es"; } if ($f[1] =~ /\@telia.net/i) { $email = "ip\@telia.net"; } } } } # end of while loop } close(WHOIS); if ($abuse_email ne "") { $email = $abuse_email; } if (($email eq "") && ($whois_arg eq "")) { if ($net_block ne "") { $whois_arg = "-a"; $sub_sip = $net_block; debug("found net_block = $net_block\n"); } } if ($email eq "") { $email = "No contact email"; } debug("Do 2nd whois whois_arg = $whois_arg\n"); if ($whois_arg ne "") { $email = ""; if (open(WHOIS, "whois $whois_arg $sub_sip |")) { while () { $line = $_; debug("2nd whois line = $line\n"); # look for invalid IP, whois returns 'No match found'. if ((/No match found for/) || (/No match!!/)) { $email = "No match found -a or -r"; last; } @f=split(/\s+/,$line); # parse into fields surrounded by blanks if (/(abuse\@[a-zA-Z0-9\.\-\_]+)/) { if (${1} =~ /\@nic.br/i) { next;} else { $abuse_email = ${1}; debug("abuse_email2 body = $abuse_email\n"); } } if (($f[0] eq "AbuseEmail:") || ($f[0] eq "OrgAbuseEmail:")) { $abuse_email = $f[1]; debug("abuse_email2 handle= $abuse_email\n"); } if (($f[0] eq "e-mail:") || ($f[0] eq "notify:") || ($f[0] eq "OrgNOCEmail:") || ($f[0] eq "OrgTechEmail:") || ($f[0] eq "TechEmail:")) { debug("email2 handle = $f[0] email2 = $f[1]\n"); $email = $f[1]; } # special for JP Japan debug("JP email2 handle = $f[1]\n"); if (($f[1] eq "[Reply") && ($f[2] eq "Mail]")) { debug("found JP email2 handle = $f[1] email2 = $f[3]\n"); $email = $f[3]; } } } close(WHOIS); if ($abuse_email ne "") { $email = $abuse_email; } if ($email eq "") { $email = "No contact email -a or -r"; } return ($email); } else { return ($email); } } sub debug { if (($verbose eq "1") | ($verbose eq "2")) { print(STDERR @_); } }