#!/usr/bin/perl5.8.4
#  This software was derived from SATAN 1.1.1 by Dan Farmer and Wietse Venema
#  (http://www.porcupine.org/satan).
#
#
# version 3, Tue Apr  4  8:58:13 1995, last mod by wietse
# version 4, Mon Nov 30 23:30:00 1998, last mod by todd
# version 6, Mon Feb 14 23:30:00 2000, last mod by todd
# version 7, wed Apr 11 23:30:00 2001, last mod by todd
# version 8, Mon Dec 25 20:00:00 2006, last mod by todd
# version 9, Sun Jan 11 20:00:00 2007, last mod by todd
#
$running_under_sara = 1;
require 5.005;
require 5.8.1;
require 'config/version.pl';
require 'config/sara.cf';
require 'perl/sara-data.pl';
require 'perl/run-sara.pl';
require 'perl/misc.pl';
require 'perl/status.pl';
require 'perl/plugins.pl';
require 'perllib/getopts.pl';	# IRIX needs it at the end.

#
# Defaults are taken from the config file. There are three ways to control
# operation: from the command line, from the sara.cf file, and from the
# HTML user interface. That's a bit much.
#
$seq = rand();
$opt_a = $attack_level;
$opt_A = $proximity_descent;
$opt_d = $sara_data;
$opt_D = $daemon;
$opt_l = $max_proximity_level;
$opt_n = $use_nmap;
$opt_o = $only_attack_these;
#$opt_x = $dont_attack_these;
$opt_p = $reduce_packet_density;
$opt_t = 1;
$opt_u = $untrusted_host;
$opt_v = 0;
$opt_z = $sub_zero_proximity;

#
# Parse JCL.
#
$usage = "usage: $0 [options] [tgt tgt tgt ..][tgt/mask_bits][tgt_start-tgt_end]

Enters interactive mode when no target host is specified.

-a		attack level (0=light, 1=normal, 2=heavy, 3=extreme, 
		4=custom0, 5=custom1, 6=custom2 default $opt_a)
-A		proximity descent (default $opt_A)
-c list		change variables (list format: \"name=value; name=value; ...\")
-C 		apply global corrections for Reporter (in rules/correct_report)
-d database	data directory (default $opt_d)
-e              enable smb password quessing through rules/smbpasswords
-D		run in daemon mode
-f 		Enable firewall analysis (deprecated)
-F file	        File of hostnames and/or IPs	
-i		ignore existing results
-I plugin	ignore named plugin (-I all ignores all plugins)
-l proximity	maximal proximity level (default $opt_l)
-n 		perform nmap (hosstype) OS fingerprinting (if nmap is available)
		Note:  use of nmap may disrupt some targets.
-o list		scan only these (default '$opt_o')
-p 		slow performance (packet density) for slow networks/hosts
-P num		increase performance by allowing num simultaneous processes
-r 		supress generation of  SARA Reports (htm, xml, csv)
-R		activate timing logic IAW rules/timing
-s option	on = enable SAN Top 10/20 reporting; off = disable
-S status_file	pathname with scanning status file (default $opt_S)
-t level	timeout (0 = short, 1 = medium, 2 = long, default $opt_t)
-T time		start SARA at specified time (time = day-hour:minutes [#]) or
                (time = yy/mm/dd-hour:minutes[#])
-u		running from an untrusted host (for rsh/nfs tests)
-U		running from a trusted host (for rsh/nfs tests)
-v		turn on debugging output
-V		print version number
-x list         stay away from these (default '$opt_x')
-X filename	stay away from hosts listed in filename
-z		when attack level becomes negative, continue at level 0
-Z		stop at attack level 0

See sara.8 man page for details.
";

&Getopts("a:A:c:Cd:DefF:iI:l:no:O:pP:rRs:S:t:T:uUvVx:X:zZ") || die $usage;

mkdir "status", 700;
$colinux = `uname -r | grep "[0-9]\-co\-[0-9]"`; 
$ENV{COLINUX}=YES if ($colinux);
  if (-f $RPCCLIENT) {
  #Check which version of rpcclient
    $mysmb = "";
    open (TEST,"$RPCCLIENT -V 2>/dev/null|");
    while (<TEST>) {
      if (/Version TNG/i || /Samba-TNG/) {
        $mysmb="TNG";
        last;
      } elsif (/Version 3\.[0-9]\.[0-9]/) {
        $mysmb="V3";
      } else {
        $mysmb = "V2";
      }
    }
    $ENV{MYSMB} = $mysmb;
  }


foreach (keys %ENV) {
       delete $ENV{SMB_PASS};
       $ENV{SMB_PASS}=1 if defined($opt_e);
}

for (split(/\s*;\s*/, $opt_c)) {
	${$name} = $value if ($name, $value) = split(/\s*=\s*/, $_, 2);
        $ENV{FW_PORTS} = $value if ($name eq "fw_ports"); 
}
$ENV{SQL_INJECT}         = $sql_inject; 
$ENV{SQL_INJECT_TIMEOUT} = $sql_inject_timeout;
$ENV{SQL_INJECT_DUMP}    = $sql_inject_dump;

$concurrent_processes = $opt_P if $opt_P;
$ENV{CONCURRENT_PROC} = $concurrent_processes;
$sans = $opt_s if $opt_s;
if ($opt_V) {
        print "SARA version $sara_version\n";
        exit 0;
}
$timing = 1 if $opt_R;

$interactive="ON";
$interactive="OFF" if $#ARGV >=0;
$interactive="OFF" if $opt_F;
$interactive="ON" if $opt_D;
if ($concurrent_processes == 1) {
  foreach (keys %ENV) {
   delete $ENV{SARA_NMAP};
   $ENV{SARA_NMAP}="ON" if defined($opt_n);
  }
} elsif($opt_n) {
  if ($interactive eq "OFF") {
    print "   High grade OS disabled, set \$concurrent processes to 1 in sara.cf\n";
  }
}
if ($interactive eq "ON") {
   print "Security Auditor's Research Assistant ($sara_version)\n";
   print "  Portions Copyright (GPL) 1999-2007 Advanced Research Corporation (R).\n";
   print "  Derived from SATAN 1.1.1 from Dan/Wietse.\n";
   &credits();
   print "\n";
   if (-f $NMAP) {
    print "  NMAP found:";
    if ($opt_n && $concurrent_processes == 1) {
         print "   High grade OS fingerprinting will be enabled\n";
    } elsif ($opt_n && $concurrent_processes != 1) {
         print "   High grade OS disabled, set \$concurrent processes to 1 in sara.cf\n";
    } else {
         print "   Use \"-n\" option on command line to enable\n";
    }
   }
   &delay_sara();
   if($MOSAIC || $opt_D) {
     print "\nSARA is starting up...\n";
   } else {
     print "\nNo Web browser found, aborting ...\n";
     exit;
   }
}

$debug = $opt_v;

# are we in daemon mode?
# if we are, SARA will invoke html() which handles
# the daemon process
$daemon = $opt_D;
if ($daemon) {
  if ($daemon_port == "") {
    print "\nSARA daemon is terminating: no port defined in config/sara.cf\n";
    exit
  } else {
    print "SARA is installed in daemon mode...\n";
  }
}
$correction = "on" if $opt_C;

@all_attacks=(\@light,\@normal,\@heavy,\@extreme,\@custom0,\@custom1,\@custom2,\@fw);
@all_modes = ("light","normal","heavy","extreme","custom0","custom1","custom2","fw");
die "bad attack level: $opt_a\n" unless $all_attacks[$opt_a];
$attack_level = $opt_a;
 foreach (keys %ENV) {
       delete $ENV{SARA_LEVEL}; 
       $ENV{SARA_LEVEL}=$opt_a;
}
$sara_data = $opt_d if "$opt_d";
$status_file = "$status_dir/status-$sara_data" if ($sara_data ne "sara-data");

 foreach (keys %ENV) {
       delete $ENV{SARA_FW}; 
       $ENV{SARA_FW}="PARTIAL" if ($opt_p == 1);
       $ENV{SARA_FW}="ON" if defined($opt_f);
}
 foreach (keys %ENV) {
       delete $ENV{SARA_HOSTS};
       $ENV{SARA_HOSTS}=$opt_F if defined($opt_F);
}
if ($opt_O) {
   print "\n  -O option no longer supported, please use -x\n\n";
   exit 1;
}
&delay_sara();
$time_to_start = $opt_T if defined($opt_T);
if ($time_to_start) {
  if ($interactive eq "ON") {
   die "Cannot use -T option in interactive mode\n";
  }
  if ($time_to_start =~ "-"){
    ($days,$hours)=split(/-/,$time_to_start);
    $hours =~ s/\#//;
    ($hr,$min)=split(/:/,$hours);
  } else {
    $days = 0;
   ($hr, $min)=split(/:/,$time_to_start);
  }
  ($s,$m,$h,$md,$mn,$yr,$wd,$yd,$is) = localtime();
#
# For the T option and full date is specified
#
  if ($days =~ "/") {
   ($yy,$mm,$dd) = split(/\//,$days);
   if ($yy <= 1999 || $mm <= 0 || $dd <= 0 || $mm > 12 || $dd > 31) {
     die "Illegal time specification for -T option\n";
   } 
   $yy = $yy - 1900;
   $mm = $mm - 1;
   if ($yr > $yy || ($yr == $yy && $mn > $mm) || ($yr == $yy && $mn == $mm && $md > $dd)) 
   {
# If time has already come and past
     if ($time_to_start =~ "#") {
       &update_status("Time has past, operation not initiated (T# option)");
       print "Time has past, operation not initiated (T# option)\n";
       exit;
     } else {
       $days = 0;
       $hr = 0;
       $min = 0;
     }
   } else {
      
# if we need to wait for the date to roll around
   $start_date = $days; $days=0;
   $wait_flag = 0;
   while ($yr != $yy || $mn != $mm || $md != $dd) {
    if ($wait_flag == 0) {
      $wait_flag = 1;
      &update_status("SARA waiting for $start_date (T option)");
      if ($debug ==1) {
        print "SARA waiting for $start_date (T option)\n";
      }
      $h = 0; $m = 0;
     }
     sleep (60);
     ($s,$m,$h,$md,$mn,$yr,$wd,$yd,$is) = localtime();
    }
   }
  }
# Common processing for days/date calculation
  $minutes_to_start=($days*1440+$hr*60+$min) - ($h*60+$m);
  if ($minutes_to_start > 0) {
   &update_status("SARA will wait $minutes_to_start minutes (T option)");
   if ($debug == 1) {
     print "SARA will wait $minutes_to_start minutes (T option)\n";
   }
   sleep($minutes_to_start*60);
   $started = localtime();
   &update_status("SARA has started on $started (T option)");
   if ($debug == 1) {
     print "SARA has started on $started (T option)\n";
   }
  }else{
   if ($time_to_start =~ "#") {
     &update_status("Time has past, operation not initiated (T# option)");
     if ($debug == 1) {
       print "Time has past, operation not initiated (T# option)\n";
     }
     exit;
   } else {
     &update_status("SARA will start now as start time has past (T option)");
     if ($debug ==1) {
       print "SARA will start now as start time has past (T option)\n";
     }
   }
  }
}

$max_proximity_level = $opt_l;
$proximity_descent = $opt_A;
$sub_zero_proximity = $opt_z;
$sub_zero_proximity = 0 if $opt_Z;

$only_attack_these = $opt_o;
$dont_attack_these .= " $opt_x";
if ($opt_X) {
  if (-f $opt_X) {
 &update_status("Host exclusions being read from $opt_X");
 print "Host exclusions being read from $opt_X\n";
    open (XCLUDE, "$opt_X");
    while (<XCLUDE>) {
      chomp;
      if (/[a-zA-Z0-9]/) {
        $dont_attack_these .= "$_ ";
      }
    }
  } else {
    print "exclusion file $opt_X not found, -X option ignored\n";
  }
}
$dont_attack_these =~ s/^\s+//;
$status_file = "$status_dir/status-$opt_S" if $opt_S;

@all_timeouts = ($short_timeout, $med_timeout, $long_timeout);
die "bad timeout: $opt_t\n" unless $all_timeouts[$opt_t];
$timeout = $all_timeouts[$opt_t];

$untrusted_host = $opt_u;
$untrusted_host = 0 if $opt_U;
# See if subnet mask was specified
($name, $subnet) = split("/", $ARGV[0]);
if ($subnet){ 
   $opt_s=1;
   $attack_proximate_subnets=1;
}
# See if IP range argument was selected
($first_ip, $last_ip) = split("-", $ARGV[0]);
if ($last_ip =~ /^\d+\.\d+\.\d+\.\d+$/) {
  if ($first_ip =~ /^\d+\.\d+\.\d+\.\d+$/) {
    $opt_s=1;
    $attack_proximate_subnets=1;
  }
}
umask 077;	# DON'T TAKE THIS OUT!!!
foreach (keys %ENV) {
       delete $ENV{SARA_DATA};
       $ENV{SARA_DATA}="$sara_data";
}
unlink <tmp*>;
$pi_name = get_plugin(); 
if ( $opt_I ne "$pi_name" &&  $opt_I ne "all") {
  if ($pi_name) {
    do 'plugins/$pi_name';
    require "plugins/$pi_name";
    $version =~ $pi_version;
    print "Plugin: $pi_title, $pi_version\n";
    print "        $pi_copyright\n\n";
  }
}
        if ($opt_r) {
          $reportwriter = 0;
          print "ReportWriter disabled\n";
        } else {
          $reportwriter = 1;
        }

if ($interactive eq "ON") {
	#
	# The HTML driver will eventually invoke init_sara() and run_sara().
	#
	require 'perl/html.pl';
	&html();
} else {
	&init_sara_data();
	&read_sara_data() unless defined($opt_i);
	&run_sara(join(' ', @ARGV));
}
