#!/usr/bin/perl -w # # Source Map www.sittinglittleduck.com v 0.9.1 # # code stolen or borrowed from (depends which way you look at it) # # $Id: automap,v 1.2 2004/03/16 10:38:16 shade Exp $ # www.wastelands.gen.nz # # use strict; use Getopt::Long; my($NMAP) = 'nmap'; my($MAX_CHILDREN) = 4; my($LAUNCH_DELAY) = 500; my($DISPLAY_ERRORS) = 0; my($OUTPUT_PREFIX) = 'nmap'; my($TEMP_DIR) = './sourceMap_output'; my($KEEP_TEMP_FILES) = 0; my($CREATED_TEMP_DIR) = 0; my(@TARGETS) = (); my(@SOURCE) = (); my(%CHILDREN); my(@COMPLETE) = (); ## ## Display usgae information ## sub usage { print < \$cl_help, "T|tcp" => \$cl_tcp, "U|udp" => \$cl_udp, "p|port=s" => \$cl_port, "s|sourcePort=s" => \$cl_source, "g|gofast" => \$cl_fast, "c|child=i" => \$MAX_CHILDREN, "d|delay=i" => \$LAUNCH_DELAY, "blat|goggan" => \$cl_blat, "i|input=s" => \$cl_input_file, "e|errors" => \$DISPLAY_ERRORS, "k|keep" => \$KEEP_TEMP_FILES, ) || exit(1); #display help usage() if $cl_help; #display help if options are set #usage() if (@ARGV == 0); die("No protocol specified!\n") if !$cl_tcp && !$cl_udp; die("Cannot specifiy both TCP AND UDP!\n") if $cl_tcp && $cl_udp; # #Setting if TCP # if ($cl_tcp) { $NMAP .= " -sS -vvv -n -P0"; $OUTPUT_PREFIX .= '-SourceScan-tcp'; } # #Setting if UDP # if ($cl_udp) { $NMAP .= " -sU -vvv -r -n -P0"; $OUTPUT_PREFIX .= '-SourceScan-udp'; } # #Setting for gofast # if ($cl_fast) { $NMAP .= " -T4 --max_rtt_timeout 2000"; }; # #Setting for ports to scan to # if ($cl_port) { $NMAP .= " -p ".$cl_port; } else { die("Please specify a target port (or range)"); } # #Setting for which source ports to use # if ($cl_source) { #check format if ($cl_source =~ /[\d\-,]+/s) { #get each item enterned while($cl_source =~ /,?(\d+-?\d*),?/gs) { #Check if it's a range $item = $1; if($item =~ /(\d+)-(\d+)/s) { $lower = $1; $upper = $2; #generate range if($lower > 0 && $upper < 65536 && $lower < $upper) { for( $a = $lower; $a <= $upper; $a++) { push(@SOURCE, $a); } } else { die("ERROR: Source ports entered $item is incorrect"); } } else { push(@SOURCE, $item); } } } else { die("Sytax for source port is wrong"); } } else { die("Please specify a source port or source port range to use"); } # #Setting for go really really fast # if ($cl_blat) { $MAX_CHILDREN = 9999; $LAUNCH_DELAY = 0; } # #Setting for reading in from a file or command line # if ($cl_input_file) { #Read in from file #open file open(IN, "<$cl_input_file")|| die("Unable to open input file: $!!\n"); #Get each line my(@temp); while () { s/^(.*)#.*$/$1/; # Strip comments s/^\s*(.*?)\s*$/$1/; # Strip whitespace next if /^$/; # Ignore blank lines my($source); my(@temp); my($a) = 0; while($a < @SOURCE) { @temp = [$_, $SOURCE[$a]]; push(@TARGETS, @temp); $a++; } #push(@TARGETS, $_); } close(IN); } else { #TODO ADD some code to deal command line entering of Addresses #Read infrom args if (scalar(@ARGV) == 0 && !$cl_input_file) { die("No targets specified!\n"); } while (my $target = shift(@ARGV)) { my($source); my(@temp); my($a) = 0; while($a < @SOURCE) { @temp = [$target, $SOURCE[$a]]; push(@TARGETS, @temp); $a++; } #push(@TARGETS, $target); } } } ## ## Create a child process running nmap against the specified target ## sub LaunchNMap { my($target) = $_[0]; my($sourceport) = $_[1]; my($pid) = fork(); if ($pid < 0) { die("Unable to fork: $!!\n"); } if ($pid > 0) { return($pid); } close(STDIN) || die("Unable to close STDIN: $!!\n"); open(STDOUT, ">/dev/null") || die("Unable to reopen STDOUT: $!!\n"); #Code to show errors if (!$DISPLAY_ERRORS) { open(STDERR, ">/dev/null") || die("Unable to reopen STDERR: $!!\n"); } #exec the nmap command exec("$NMAP --source_port $sourceport -oA $TEMP_DIR/$OUTPUT_PREFIX-$target-$sourceport $target") || die("Unable to launch NMap: $!!\n"); } # #End of subs # # #Start of running code # ProcessCommandLine(); die("Must be root!\n") if $> != 0; if (! -d $TEMP_DIR) { mkdir($TEMP_DIR, 0770) || die("Failed to create temporary directory: ($!)\n"); $CREATED_TEMP_DIR = 1; } print "Source mapping ",scalar(@TARGETS)," targets\n"; while (keys(%CHILDREN) || @TARGETS) { my($pid) = wait; if (exists($CHILDREN{$pid})) { print "Scan against $CHILDREN{$pid} is complete\n"; push(@COMPLETE, $CHILDREN{$pid}); delete($CHILDREN{$pid}); } while (@TARGETS && keys(%CHILDREN) < $MAX_CHILDREN) { my($target) = shift(@TARGETS); my($left) = scalar(@TARGETS); print "Launching nmap against $target->[0] on source port $target->[1] ($left targets remaining)\n"; my($child_pid) = LaunchNMap($target->[0], $target->[1]); $CHILDREN{$child_pid} = "$target->[0]-$target->[1]"; if (keys(%CHILDREN) < $MAX_CHILDREN) { select(undef, undef, undef, $LAUNCH_DELAY / 1000); } } } unlink("$OUTPUT_PREFIX.nmap"); unlink("$OUTPUT_PREFIX.gnmap"); unlink("$OUTPUT_PREFIX.xml"); foreach my $target (@COMPLETE) { system("cat $TEMP_DIR/$OUTPUT_PREFIX-$target.nmap >> $OUTPUT_PREFIX.nmap"); system("cat $TEMP_DIR/$OUTPUT_PREFIX-$target.gnmap >> $OUTPUT_PREFIX.gnmap"); system("cat $TEMP_DIR/$OUTPUT_PREFIX-$target.xml >> $OUTPUT_PREFIX.xml"); } #TODO add code to generate a better report, that is a little bit more readable! if (!$KEEP_TEMP_FILES) { foreach my $target (@COMPLETE) { unlink("$TEMP_DIR/$OUTPUT_PREFIX-$target.nmap"); unlink("$TEMP_DIR/$OUTPUT_PREFIX-$target.gnmap"); unlink("$TEMP_DIR/$OUTPUT_PREFIX-$target.xml"); } rmdir($TEMP_DIR) if $CREATED_TEMP_DIR; }