#!/usr/local/bin/perl # A perl script for finding echo response packets. # The major change is a new summary table that counts hits from # a source IP to an entire class C net and a threshold variable # ($SCAN_LIMIT, default 5). After SCAN_LIMIT packets are seen from # a source to a net further packets from that source to the net # are suppressed in the next table (further down there is still # a complete table) and the count is displayed in the first table # (again below the summaries there is a complete copy of the # table if needed). You can search for "###" to find the start # of a table, and for "---" to get to the end of the summary # tables and start of the full tables (so you can delete them # easily if you don't want them). The change is because of gag # scans. The original gets unwieldy under a multi subnet gag # scan (I haven't seen one yet so it hadn't bitten me, but # undoubtably will :-) ) with the summarization and threshold # you should still be able to see attacks on individual machines # even while a scan or scans is going on. # Peter Van Epp / Operations and Technical Support # when SCAN_LIMIT is exceeded for a source ip dest net pair the detail recording # of the source and destination ip pairs stops (for table size limits) but # further hits are counted in the source ip to dest net count (the first # table). Change the limit to suit your taste (or tolorance). $SCAN_LIMIT = 5; open(STDIN,$ARGV[0]) || die "Can't open $ARGV[0]: $!\n" if $ARGV[0]; $line = 0; $start_time = ""; $end_time = ""; while () { $line ++; if (($line % 10000) == 0) { print STDERR "Processing $line\n"; } chop; $src_bytes = " "; $dest_bytes = " "; $source_net =""; $dest_net =""; $src_port = " "; $dst_port = " "; ($date, $flag, $rest) = unpack("A18 A5 A200",$_); if ($start_time eq "") { $start_time = $date; } ($type, $rest) = split(' ',$rest,2); if ($type eq "man") { $mid_flag = ' '; ($source_ip, $dest_ip, $src_pkt, $dest_pkt, $src_bytes, $dest_bytes, $end_flag) = split(' ',$rest,7); } elsif ($type eq "icmp") { ($source_ip, $mid_flag, $dest_ip, $src_pkt, $dest_pkt, $end_flag) = split(' ',$rest,6); if ($end_flag =~ /port/) { ($t, $p, $dst_port, $rest) = split(' ',$end_flag); } ($a,$b,$c,$d)= split(/\./,$source_ip); ($e,$f,$g,$h)= split(/\./,$dest_ip); } else { ($source_ip, $mid_flag, $dest_ip, $src_pkt, $dest_pkt, $src_bytes, $dest_bytes, $end_flag) = split(' ',$rest,8); ($a,$b,$c,$d,$src_port)= split(/\./,$source_ip); ($e,$f,$g,$h,$dst_port)= split(/\./,$dest_ip); } $source_ip = "$a.$b.$c.$d"; $source_net = "$a.$b.$c"; $dest_ip = "$e.$f.$g.$h"; $dest_net = "$e.$f.$g"; if ($type eq "icmp") { if ($end_flag eq "ECO" || $end_flag eq "ECR") { $all_data{"$dest_ip"} .= "$date $source_ip $mid_flag $dest_ip $end_flag\n"; } if ($end_flag eq "ECR") { # Sometimes argus gets source and dest reversed, so correct everything to one # format ... if ($mid_flag eq "<-") { $tmp = $source_ip; $source_ip = $dest_ip; $dest_ip = $tmp; $tmp = $source_net; $source_net = $dest_net; $dest_net = $tmp; $mid_flag = "->"; } $ecr_dest_net_data{"$source_ip $dest_net"} += 1; if ($ecr_dest_net_data{"$source_ip $dest_net"} < $SCAN_LIMIT) { $ecr_src_data_limited{"$source_ip"} .= "$date $source_ip $mid_flag $dest_ip $end_flag\n"; $ecr_dest_data_limited{"$dest_ip"} .= "$date $source_ip $mid_flag $dest_ip $end_flag\n"; } $ecr_src_data{"$source_ip"} .= "$date $source_ip $mid_flag $dest_ip $end_flag\n"; $ecr_dest_data{"$dest_ip"} .= "$date $source_ip $mid_flag $dest_ip $end_flag\n"; } } } $end_time = $date; print "Search for '###' to find next table header, search for '---' for full data\n\n*** Data from $start_time til $end_time\n\n"; print "### Unsolicited echo response by source IP and destination net count summary\n\t(counts greater than SCAN_LIMIT)\n\n"; foreach $source (sort (keys %ecr_dest_net_data)) { if ($ecr_dest_net_data{$source} >= $SCAN_LIMIT) { ($src, $dst) = split(' ',$source); write; } } print "\n### Only echo response data sorted by destination machine less than SCAN_LIMIT\n\n"; foreach $source (sort (keys %ecr_dest_data_limited)) { print "$ecr_dest_data_limited{$source}\n"; } print "\n### Only echo response data sorted by source machine less than SCAN_LIMIT\n\n"; foreach $source (sort (keys %ecr_src_data_limited)) { print "$ecr_src_data_limited{$source}\n"; } print "---\n### Unsolicited echo response by source IP and destination net count summary\n\n"; foreach $source (sort (keys %ecr_dest_net_data)) { ($src, $dst) = split(' ',$source); write; } print "\n### Only echo response data sorted by destination machine\n\n"; foreach $source (sort (keys %ecr_dest_data)) { print "$ecr_dest_data{$source}\n"; } print "\n### Only echo response data sorted by source machine\n\n"; foreach $source (sort (keys %ecr_src_data)) { print "$ecr_src_data{$source}\n"; } print "\n### All echo data\n\n"; foreach $source (sort (keys %all_data)) { print "$all_data{$source}\n"; } format STDOUT = @<<<<<<<<<<<<<<< @<<<<<<<<<<< @>>>>>>>>>>>>>>>>> $src, $dst, $ecr_dest_net_data{$source} .