\n"; if (param('bdate') =~ /^\d{8}\$/ and param('bdate') > 20081202) { \$basedate = param('bdate'); } else { \$bdate = time - 86400; # - 172800; \$basedate = strftime "%Y%m%d", localtime \$bdate; } print " Base Date (Initial Scan YYYYMMDD)
\n"; if (param('sdate') =~ /^\d{8}\$/ and param('sdate') > 20081202) { \$scandate = param('sdate'); } else { \$sdate = time; \$scandate = strftime "%Y%m%d", localtime \$sdate; } print " Scan Date (Compair Scan YYYYMMDD)
\n"; if (\$sdate < \$bdate) { die("Base Date can NOT be BEFORE the Scan Date"); } if ( param('ip') =~ /^(\d{1,3}\.\d{1,3})\$/ or param('ip') =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\$/ ) { \$ip = \$1; \$opt_s = \$ip; } elsif ( param('ip') =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\$/ ) { \$ip = \$1; \$opt_i = \$ip; } print " Search IP (Partial IP Works XXX.XXX)
\n"; print "\n"; print "
```\n";
} else {
\$sdate = time; # - 86400;
if (\$opt_b > 2) {
\$bdate = time - \$opt_b * 86400;
} else {
\$bdate = time - 86400; # - 172800;
}
\$basedate = strftime "%Y%m%d", localtime \$bdate;
\$scandate = strftime "%Y%m%d", localtime \$sdate;
}
if (\$opt_i =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}/) {
\$opt_s = \$1;
}
print "Compairing \$basedate to \$scandate\n" if (\$opt_v or \$opt_d);

opendir(DIR, \$logdir) or die "ERROR: Unable to open \$logdir: \$!\n";
close(DIR);

if (\$opt_m) {
open(STDOUT,"| \$sendmail -t") or die "Unable to open sendmail";
print "To: \$opt_m\n";
print "Subject: Port Changes from \$basedate to \$scandate\n\n";
}
FILE: for \$file (@dir) {
next FILE if (\$file =~ /^\./);
next FILE if (\$opt_s and \$file !~ /\$opt_s/);
print "examining \$file\n" if (\$opt_d > 3);
if (\$file =~ /^\$basedate(\.\d{1,3}\.\d{1,3}\.\d{1,3}\.gnmap)\$/) {
\$exten = \$1;
print "compairing \$basedate\$exten to \$scandate\$exten\n" if (\$opt_d);
open (BASE, "\$logdir/\$basedate\$exten");
@base = ;
close (BASE);
open (SCAN, "\$logdir/\$scandate\$exten");
@scan = ;
close (SCAN);
@base = grep(!/^#/, @base);
@scan = grep(!/^#/, @scan);
LINE: for \$cur_scan (@scan) {
my \$data;
chomp \$cur_scan;
(\$host, \$ports, \$ignored) = split ("\t", \$cur_scan);
(\$title, \$ip, \$dns) = split(' ', \$host);
next LINE if (\$opt_i and \$ip ne \$opt_i);
(\$title, \$port_info) = split(':', \$ports);
next LINE if (\$title ne "Ports");
print "\$cur_scan\n" if (\$opt_d > 3);
for \$base_scan ( grep(/\s\$ip\s/, @base) ) {
chomp \$base_scan;
print "\$ip found in both files\n" if (\$opt_d);
next LINE if (\$cur_scan eq \$base_scan);
print "Base Scan and New Scan do not Match\n" if (\$opt_d);
print "\$cur_scan\n\$base_scan\n" if (\$opt_d > 3);
(\$bhost, \$bports, \$bignored) = split ("\t", \$base_scan);
if (\$ignored ne \$bignored and (\$opt_v and \$opt_d)) {
print "IGNORED entry changed: \$bignored -> \$ignored\n";
}
next if (\$bports eq \$ports);
(\$btitle, \$bip, \$bdns) = split(' ', \$host);
(\$btitle, \$bport_info) = split(':', \$bports);
next if (\$btitle ne "Ports");
@bports = split(',', \$bport_info);
if (\$dns ne \$bdns and (\$opt_v or \$opt_d)) {
print "DNS entry changed: \$bdns -> \$dns\n";
}
for \$port_det (@bports) {
\$port_det =~ s/\s//g;
(\$port, \$state, \$proto, \$info, \$name) = split('/',\$port_det);
\$base_port{\$port} = \$state;
}
@ports = split(',', \$port_info);
if (\$#ports ne \$#bports and \$opt_d) {
print "Number of ports changed: \$#bports -> \$#ports\n";
}
for \$port_det (@ports) {
\$port_det =~ s/\s//g;
(\$port, \$state, \$proto, \$info, \$name) = split('/',\$port_det);
print "Compairing \$ip:\$port - \$base_port{\$port} => \$state\n" if (\$opt_d > 1);
if (\$state) {
if (
\$base_port{\$port} eq 'filtered'
and \$state eq 'open'
) {
print "Filtered -> Open \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  +%5u/tcp   open   %s\n", \$port, \$name);
} elsif (
\$base_port{\$port} eq 'closed'
and \$state eq 'open'
) {
print "Closed -> Open \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  +%5u/tcp   open   %s\n", \$port, \$name);
} elsif (
\$base_port{\$port} eq 'open'
and \$state eq 'filtered'
and \$opt_v
) {
print "Opened -> Filtered \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  -%5u/tcp   open   %s\n", \$port, \$name);
} elsif (
\$base_port{\$port} eq 'open'
and !\$state
) {
print "GONE \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  -%5u/tcp   open   %s\n", \$port, \$name)
unless (!\$opt_v);
} elsif (
!\$base_port{\$port}
and \$state eq 'open'
) {
print "Opened from N/A \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  +%5u/tcp   open   %s\n", \$port, \$name)
unless (!\$opt_v);
} elsif (
\$base_port{\$port} eq 'open'
and \$state eq 'closed'
and \$opt_v
) {
print "Opened -> Closed \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("  -%5u/tcp   open   %s\n", \$port, \$name);
} elsif (
\$base_port{\$port} eq 'closed'
and \$state eq 'filtered'
and \$opt_d
and opt_v
) {
print "Closed -> Filtered \$ip:\$port\n" if (\$opt_d > 1);
} elsif (
\$base_port{\$port} eq 'filtered'
and \$state eq 'closed'
and \$opt_d
and \$opt_v
) {
print "Filtered -> Closed \$ip:\$bport\n" if (\$opt_d > 1);
} elsif (
\$base_port{\$port} eq 'open'
and \$state eq 'open'
) {
print "No change here, echoing state \$ip:\$port\n" if (\$opt_d > 1);
\$data .= sprintf("   %5u/tcp   open   %s\n", \$port, \$name);
}
}
}
if ( \$data =~ /\s[\-\+]\s/ ) {
print "\$ip \$dns\n";
print "\$data\n";
print "-" x 70 . "\n\$port_info\n\$bport_info\n" if (\$opt_d > 2);
}
print "-" x 70 . "\n" if (\$opt_d);
}
}
} else {
next FILE;
}
}
if (\$opt_m) {
close (STDOUT);
}
1;

sub usage {
print " : nmap-diff - v\$VERSION - MadHat (at) Unspecific.com\n";
print " : http://www.unspecific.com/nmap/diff/\n\n";

print <<_EOF_;
nmap-diff is designed to be used with the log files
generated from the nmap-wrapper

\$0 [-hv] [-s ] [-i ] [-b ]  \
[-m ] [-l ]

-h help (this stuff)
-v is for verbose.  This will add all changed ports.
Default is to only who new open ports
-s  shows only thaing in that subnet.
At this time the subnet accepted is a class C only.
-i  only reports on that specific IP.
-b  sets the base to  days back and compares
to yesterday's scan.  so -b 7 will compare the current
scan to the scan from 1 week ago
-l  to specify where the log directory
This can be hard coded by editing the script
-m  to email the output to  when the report
is generated

_EOF_
exit 1;
}
```