#!/usr/bin/perl5.8.4
# 
# smb.sara attempts to open smb shares and reports those that are public
#
# usage: smb.sara [-a account] [-p password] [-d directory] [-s sleep [-v] host
# 
# smb.sara requires a preloaded samba configuration in /usr/local/samba.  If
# not found, smb.sara will give a "zwoi" error.
#
# Note:  sara does not provide the samba envrionment!
# 
# Author:  Advanced Research Corporation  14 Sep 98 [last updated 23 Jun 07]
# Developer:  This routine was developed with assistance of Advanced Research 
# Corporation (r). The main routine is derived from smbls code.
#
# Updated 25 Jul 2000 to distinguish between share level and user level access
# Updated 10 Oct 2000 to fix false positives in open accounts and large shares
# Updated 10 Oct 2001 to detect possible null session vulnerabilities
# Updated 13 Jan 2003 added and fixed SARA5 enhancements
# Updated 24 May 2003 added registry tests via samba-tng rpcclient
# Fixed   21 Oct 2003 registry logins to prevent lockouts
# Updated 21 Oct 2003 to generate Windows Domain
# Updated 12 Jan 2004 to stealthly probe user passwords
# Updated 19 Feb 2004 does domain logins as well as local
# Updated 24 May 2004 uses ip instead of hostname for rpc calls; tests for lsaenumsids
# Updated 24 Jan 2006 added the dnt_smb_guess switch. 
# Updated 28 May 2007 to provide support for samba-3x
# Updated 10 Nov 2007 to add additional vulnerable servers
#require 'config/paths.pl';
require 'config/sara.cf';
require 'perl/misc.pl';
require 'config/sara.cf';
require 'perl/get_host.pl';
require 'perllib/getopts.pl';
require 'rules/smb.rules';
$sid_file = "rules/sid.def";
$mysmb = $ENV{MYSMB};
exit if ($mysmb !~ /V3/ && $mysmb);
$tmp_smbpasswords= $ENV{SMB_PASS}  if($ENV{SMB_PASS});
$dont_smb_guess  = $ENV{SMB_GUESS} if($ENV{SMB_GUESS} eq "0");
$dont_smb_guess  = $ENV{SMB_GUESS} if($ENV{SMB_GUESS} eq "1");
$sara_data       = $ENV{SARA_DATA} if ($ENV{SARA_DATA});
$use_smbpasswords = $tmp_smbpasswords if $tmp_smbpasswords;
#
Getopts("a:d:p:rs:v");
if ($#ARGV != 0 ) {
      die "Usage: smb.sara [-a account] [-p password] [-d directory] [-r] [-v] [-s <sleep time (sec)>] target";
}
$nmblookup=$NMBLOOKUP;
$smbclient=$SMBCLIENT;
$rpcclient=$RPCCLIENT;
$msg_disabled_account="NT_STATUS_ACCOUNT_DISABLED";
$msg_lockout_account="NT_STATUS_ACCOUNT_LOCKED_OUT";
$default_accounts  = "sarauser,Administrator,Guest";
(@default_passwords) = ("","\%USER");
$lockout_count;
$netbios="";
$login = "";
$share = "";
$sara_shares = "";
$visible = "";
$v_share = "";
$awk=$AWK;
$visible     = 0;
$SMB_TIMEOUT = 3;
$smbname = "";
$REGISTRY    ="bin/registry.sara";
$target=$ARGV[0];
$ip = &get_host_addr($target);
#
#  Check for samba programs
#
if ( -e $nmblookup && -e $smbclient && -e $rpcclient) {
  $printed=0;
#
# get NetBIOS name
#

  open (INBIOS, "$nmblookup -A $ip 2>/dev/null|");
  while (<INBIOS>) {
    chop;
    if ( $_ =~ /<00> -   /) {
      @name = split("<", $_);
      $name[0]  =~ s/ //g;
      $name[0]  =~ s/\t//g;
      if ($name[0]) {
        $netbios = "$name[0]";
        $netbios =~ s/IS~//;
      }
    } elsif ( $_ =~ /<00> - <GROUP>/){
      @domain = split("<", $_);
      $domain[0]  =~ s/ //g;
      $domain[0]  =~ s/\t//g;
      $netdomain = "$domain[0]";
      $netdomain =~ s/IS~//;
    } elsif (/MAC Address = /) {
      ($dum, $host_mac) = split(/\= /);
      $host_mac =~ s/\-/:/g;
      &update_mac($target, $host_mac);;
    }
  }
  close (INBIOS);
  if ( $netbios ) {
    $status = "a";
    $service = "netbios-ssn";
    $trustee = "";
    $trusted = "";
    $severity = "";
    $text = "$netbios";
    $service_output = "Netbios Name";
    &sara_print();
#
    if ($host_mac) {
      $text = $host_mac;
      $service_output = "MAC ADDR";
      &sara_print();
    }
  }
  if ( $netdomain ) {
    $status = "a";
    $service = "netbios-ns";
    $trustee = "";
    $trusted = "";
    $severity = "";
    $text = "$netdomain";
    $service_output = "Netbios Domain";
    &sara_print();
  }
#
#  If no netbios name found, then we have to kludge the user lookup
#
  if (!$netbios) {
    $netbios = "\\$target";
    $host_users = "";
    $host_user_cnt = 0;
    $ENUM = "$rpcclient $ip -U \"\"\%\"\" -c \"lsaenumsid;quit\" 2>/dev/null|";
    open(IPC, "$ENUM");
    while (<IPC>) {
      chomp;
      $mysid = $_;
      $LOOKUP="$rpcclient $ip -U \"\"\%\"\" -c \"lookupsids $mysid;quit\" 2>/dev/null|";
      open(IPC0, "$LOOKUP");
      while (<IPC0>) {
        if (/S\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-/) {
          print "$_\n" if ($opt_v);
          ($dum, $user) = split(/\s+/);
          $host_users .= ",$user";
          $host_user_cnt++;
        }
      }
        close (IPC0);
     }
     $host_users =~ s/^,//;
     close (IPC);
     if ($host_users) {
      $service = "users";
      $trustee = "";
      $trusted = "";
      $severity = "";
      $text = "$host_users";
      $service_output = "$host_user_cnt accounts have been found";
      &sara_print();
      $status = "a";
      $service = "netbios-ssn";
      $trustee = "ANY\@ANY";
      $trusted = "ANY\@ANY";
      $sid     = "SMB-008";
     ($severity,$service_output,$text) = &get_sid($sid);
     &sara_print();


    }

  } else {
#
#  See if we can get SIDs for Domain and localmachine
#
    $NETSIDcmd = "lookupnames $netdomain; lookupnames $netbios; quit";
    $NETSID  = "$rpcclient \-U \"\"\%\"\" \-c \"$NETSIDcmd\" $ip 2>/dev/null|";
    open(IPC, "$NETSID");
    while (<IPC>) {
      if (/$netdomain /) {
        ($dum,$domain_sid) = split(/\s+/); 
      }     
      if (/$netbios /) {
        ($dum, $netbios_sid) = split(/\s+/);
      }
    }
  }
#
# Check for possibility for Null Sessions
#
  $mynetbios = 0;
  if (-e $rpcclient) {
    $SRVINFO = "$rpcclient -U \"\"\%\"\" -c \"srvinfo;quit\" $ip 2>/dev/null|";
    open(IPC, "$SRVINFO");
    while (<IPC>) {
      print $_ if $opt_v;
      if (/os version      :/ || /Vista/) {
        if (/Vista/) {
          ($dum, $host_os) = split(/OS\=\[/);
          ($host_os, $dum) = split(/\]/, $host_os); 
          $host_os =~ s/\(TM\) //;
        } else { 
         ($dum, $host_os) = split(/\:/);
         $host_os =~ s/\s+//g;
         $host_os = "Windows NT" if ($host_os =~ /4.0/);
         $host_os = "Windows 2000" if ($host_os =~ /5.0/);
         $host_os = "Windows XP" if ($host_os =~ /5.1/);
         $host_os = "Windows 2003" if ($host_os =~ /5.2/);
        }
	if ($host_os =~ /[a-zA-Z]/) {
          $status = "a";
          $service = "host";
          $trustee = "";
          $trusted = "";
          $severity = "";
          $text = "";
          $service_output = "HOST $host_os";
          &sara_print();
	}  
      }
      if(/platform_id/) {
         $status = "a";
         $service = "netbios-ssn";
         $trustee = "ANY\@ANY";
         $trusted = "ANY\@ANY";
         $severity = "ycio";
         $text ="SMB: Null Sessions possible from arbitrary users";
         $service_output = "Null Sessions";
         &sara_print(); 
      }
    }
   close(IPC);
  }
  $printed = 0;
  $host_users = "";
  $host_usrs_cnt = 0;
#
#  Derive users from SIDS (based on host root sid).  We will increment sids from 1000-1128
#  Need to do this as lsaenumsids does not always list them all
#
  if ($domain_sid) {
    $domain_users = ""; 
    $domain_user_cnt = 0;
    $ENUM = "$rpcclient $ip -U \"\"\%\"\" -c \"lsaenumsid;quit\" 2>/dev/null|";
    open(IPC, "$ENUM");
    while (<IPC>) {
      chomp;
      if (! /$netbios_sid/) {
      $mysid = $_;
      $LOOKUP="$rpcclient $ip -U \"\"\%\"\" -c \"lookupsids $mysid;quit\" 2>/dev/null|"; 
      open(IPC0, "$LOOKUP");
      while (<IPC0>) {
        if (/S\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-/) {
          print "$_\n" if ($opt_v);
          ($dum, $user) = split(/\s+/);
          $domain_users .= ",$user";
          $domain_user_cnt++;
         }
        }
       close (IPC0);
      }
    }
    $domain_users =~ s/^,//;
    close (IPC);
    if ($domain_users) {
      $service = "users";
      $trustee = "";
      $trusted = "";
      $severity = "";
      $text = "$domain_users";
      $service_output = "$domain_user_cnt domain  accounts have been found";
      &sara_print();

    }
  if ($netbios_sid) {
    $host_users = "";
    $host_user_cnt = 0;
    $cmd = "";
    for (500..505,1000..1300) {
      $cmd .= "lookupsids $netbios_sid-$_;";
    }
    $cmd .= "quit";
    open(IPC, "$rpcclient -U \"\"\%\"\" -c \"$cmd\"  $ip 2>/dev/null|");
    while (<IPC>) {
       chomp;
       if (/S\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-/) {
          print "$_\n" if ($opt_v);
          $unknown_cnt = 0;
          ($dum, $user) = split(/\s+/);
          $user =~ s/$netbios\\//; 
           $host_users .= ",$user";
           $host_user_cnt++;
       }
     }
     $host_users =~ s/^,//;
     close (IPC);
     if ($host_users) {
       $service = "users";
       $trustee = "";
       $trusted = "";
       $severity = "";
       $text = "$host_users";
       $service_output = "$host_user_cnt local accounts have been found";
       &sara_print();
     }
   }
 }
 if ($domain_users || $host_users) {
   $status = "a";
   $service = "netbios-ssn";
   $trustee = "ANY\@ANY";
   $trusted = "ANY\@ANY";
   $sid     = "SMB-008";
   ($severity,$service_output,$text) = &get_sid($sid);
   &sara_print();
 } 

#
 $pass_cnt = 0;
 if ($use_smbpasswords == 1 || $opt_s) {
   if (open(PASS, "rules/auth-data/smbpasswords") == 1) {
     @default_passwords = ("");
     while (<PASS>) {
       chomp;
       if (! /^#/) {
         $default_passwords[$pass_cnt] = "$_";
         $pass_cnt++;
       }
     }
   }
     close(PASS);
 } 
 if (! $host_users && ! $domain_users) {
   $printed = 0;
   $host_users = "";
   $host_user_cnt = 0;
   if (-e $rpcclient) {
     $USER="$rpcclient -U \"\"\%\"\" -c \"enumdomusers;quit\" $ip 2>/dev/null|";
     open(IPC, "$USER");
      while (<IPC>) {
        print $_ if $opt_v;
        if (/^user:/) {
          ($dum, $tmp) = split(/\[/);
          ($tmp, $dum) = split(/\]/, $tmp);
          if ($tmp =~ /[a-zA-Z]/) { 
            $host_users .= "$tmp,";
            $host_user_cnt++;
          } 
           
        } 
      }
          if ($host_users) {
            $status = "a";
            $service = "netbios-ssn";
            $trustee = "ANY\@ANY";
            $trusted = "ANY\@ANY";
            $sid     = "SMB-007";
            ($severity,$service_output,$text) = &get_sid($sid);
            &sara_print();
            $printed = 1;
            $host_users =~ s/,\$//;
            $status = "a";
            $service = "users";
            $trustee = "";
            $trusted = "";
            $severity = "";
            $text = "$host_users";
            $service_output = "$host_user_cnt accounts have been found";
            &sara_print();
	  }  
      close(IPC);
   } 
# } else { 
#    $status = "a";
#    $service = "netbios-ssn";
#    $trustee = "ANY\@ANY";
#    $trusted = "ANY\@ANY";
#    $sid     = "SMB-007";
#    ($severity,$service_output,$text) = &get_sid($sid);
#    &sara_print();
#    $printed = 1;
}
if ($domain_users &&  ! $dont_smb_guess == 1) {
   (@d_users) = split (/,/,$domain_users);
}
if ($host_users && ! $dont_smb_guess == 1) {
    $host_users = "sarauser,$host_users";
    (@users) =split(/,/,$host_users);
} else { 
    $host_users = $default_accounts;
    (@users) =split(/,/,$host_users);
}
if ($opt_a) {
   (@users)   = ($opt_a);
   (@d_users) = ($opt_a);
}
#
#
#  Get a list of shares (go through the following accounts)
#  as specified in rules/
#      sarauser (bogus user) 
#      guest
#      administrator
#
$open_accounts = "";
if ($netbios || $_netbios) {
  $netbios = $_netbios if ($_netbios);
  for (@users) {
    $_user = $_;
    $thisdomain = "$_domain";
    $visible = &smb_check($_user);
    $v_share = 1 if ($visible ==2 && $_user eq "sarauser");
    if ($visible != 0 && $v_share == 0){
      $sid     = "SMB-004";
      ($severity,$service_output,$text) = &get_sid($sid);
      $status = "a";
      $service = "netbios-ssn";
      $trustee = "ANY\@$target";
      $trusted = "ANY\@$target";
      $text .= " \($thisdomain\\$_user\)" if ($_user ne "sarauser");
      $v_share = 1 if ($_user eq "sarauser"); 
      &sara_print();
    }
  }
  for (@d_users) {
    $_user = $_;
    $thisdomain = "";
    $visible = &smb_check($_user);
    if ($visible != 0 && $v_share == 0){
      $sid     = "SMB-004";
      ($severity,$service_output,$text) = &get_sid($sid);
      $status = "a";
      $service = "netbios-ssn";
      $trustee = "ANY\@$target";
      $trusted = "ANY\@$target";
      $text .= "  \($thisdomain\\$_user\)" if ($_user eq "sarauser");
      &sara_print();
    }
  }
 }
#MARK
}else {
          $sid     = "SMB-005";
          ($severity,$service_output,$text) = &get_sid($sid);
          $status  = "a";
          $service = "netbios-ssn";
          $trustee = "ANY\@$target";
          $trusted = "ANY\@$target";
          $severity = "zwoi";
          &sara_print();
}
exit 1;
sub smb_check {
   $open_accounts = "";
   $smb_read = 0;
   $account  = $_;
   $visible  = 0;
   $_printed = 0;
   $disabled_account = 0;
   @tmp_passwords = @default_passwords;
   @tmp_passwords = $opt_p if $opt_p;
   for (@tmp_passwords) {
     next if /^#/;
     if ($use_smbpasswords == 1 && $delay_smbpasswords) {
       sleep $delay_smbpasswords;
     } elsif ($opt_s) {
       print "Delaying $opt_s between password guesses\n" if $opt_v;
       sleep $opt_s;
     }
     $password = "$_";
     $password =~ s/\%USER/$account/;
     $password =~ s/\%NETBIOS/$netbios/;
#     $password = lc($password);
     $login = "";
     @list="";
#
# Check for Open Shares
#
#        open (IN,"$smbclient  $target -L "\/\/$netbios" -U \"$account%$password\" -W \"$thisdomain\" -N 2>&1|");
       open(IN, "$smbclient -L $ip -U \"$account%$password\" -W \"$thisdomain\" -N 2>&1|");
       @list = <IN>;
 for (@list) {
       if (/Server\=\[/ && ! $smbname) {
         ($dum, $smbname) =split(/Server\=\[/);
         $smbname =~ s/\]//g;
	 $smbname =~ s/\n//g;
	 $smbname =~ s/\s+$//;
         $status = "a";
         $service = "netbios-ssn";
         $trustee = "";
         $trusted = "";
         $severity = "";
         $text = "$smbname";
         $service_output = "SMB Name";
         &sara_print();
	 if ($smbname =~ /Samba 3\.0\.25r$/ 
	 || $smbname =~ /Samba 3\.0\.2[0-4]/ || \
	    $smbname =~ /Samba 3\.0\.1[0-9]/ || $smbname =~ /Samba 3\.0\.[0-9]$/) {
            $sid     = "SMB-010";
            ($severity,$service_output,$text) = &get_sid($sid);
            $status  = "a";
            $service = "netbios-ssn";
            $trustee = "ANY\@$target";
            $trusted = "ANY\@$target";
	    &sara_print();
         } elsif ($smbname =~ /Samba 3\.0\.25/) {
            $sid     = "SMB-011";
            ($severity,$service_output,$text) = &get_sid($sid);
            $status  = "a";
            $service = "netbios-ssn";
            $trustee = "ANY\@$target";
            $trusted = "ANY\@$target";
            &sara_print();
         } elsif ($smbname =~ /Samba 3\.0\.26/) {
            $sid     = "SMB-012";
            ($severity,$service_output,$text) = &get_sid($sid);
            $status  = "a";
            $service = "netbios-ssn";
            $trustee = "ANY\@$target";
            $trusted = "ANY\@$target";
            &sara_print();
	 }   
         
         if (! $host_os) {
            ($dum, $host_os) = split(/OS\=\[/);
            if (/Vista/) {
              ($dum, $host_os) = split(/OS\=\[/);
              ($host_os, $dum) = split(/\]/, $host_os);
              $host_os =~ s/\(TM\) //;
            } else {
              $host_os =~ s/\s+//g;
              $host_os = "Windows NT" if ($host_os =~ /4.0/);
              $host_os = "Windows 2000" if ($host_os =~ /5.0/);
              $host_os = "Windows XP" if ($host_os =~ /5.1/);
              $host_os = "Windows 2003" if ($host_os =~ /5.2/);
            }
            $status = "a";
            $service = "host";
            $trustee = "";
            $trusted = "";
            $severity = "";
            $text = "";
            $service_output = "HOST $host_os" if ($host_os =~ /[a-zA-Z]/);
            &sara_print();
         }
       }
}
       print "@list\n" if $opt_v;
       print "Testing account $thisdomain\\$account with password $password\n" if $opt_v;
       for ($i = 1; $i <= 15; $i++) {
         $login = "YES" if (grep(/ Disk /,$list[$i]) && $share eq "");
       }
       next if (grep(/$msg_disabled_account/, $list[$i]));
       if ($login && $account eq "sarauser") {
         $login = "";
         $share = "YES";
       }
#     $netbios[$i] =~ s/\n//;
       chomp($netbios);
       for ($i = 1; $i <= 50; $i++) {
         if (grep(eval(/    Disk    /), $list[$i])){
           $list[$i] =~ s/\A\t//;
           ($list[$i]) = ($list[$i] =~ /(\A.{0,13})/);
           ($sname, $type, $comment) = split(/   /,$list[$i], 3);
           $tmp_sname = $sname;
           $tmp_sname =~ s/\$/DOLLAR/g;
           if ($sara_shares !~ /$tmp_sname/ || $account eq "sarauser") {
             $ret = 0;
             $visible = 1;
             $ret = &smb ($sname) if (!$opt_d || ($opt_d eq $sname));
             if ($ret != 0) {
               $smb_read = 1;
               $sid     = "SMB-001";
              ($severity,$service_output,$text) = &get_sid($sid);
              $status  = "a";
              $service = "netbios-ssn";
              $trustee = "ANY\@$target";
              $trusted = "ANY\@$target";
              $text = " $text $sname";
              $text .= " (r/w)" if $ret == 2;
              $text .= " ($thisdomain\\$account)" if ($account ne "sarauser");
              &sara_print();
              $_printed = 1;
              $login = "YES" if ($share eq "");
              $sara_shares .= "$tmp_sname " if $account eq "sarauser";
            }
          }
        }
      if ($sname=''){ $i=30;}
      }
     if ($login) {
# Check Registry
#
       open(REGISTRY,"$REGISTRY -u \"$account\" -p \"$password\" $target|");
       while (<REGISTRY>) {
         print "$_" if $opt_v;
       }
       close (REGISTRY);
       if ($smb_read == 1) {
           $sid = "SMB-002";
           $sid = "SMB-003" if $password;
           ($severity,$service_output,$text) = &get_sid($sid);
           $status  = "a";
           $trustee="ANY\@ANY";
           $trusted="ANY\@ANY";
           $text = " $text $thisdomain\\$account";
           $login ="";
           &sara_print();
          $printed=1;
       }
      last;
     }
     last if ($account eq "sarauser");
    }
# }
#}
   close (IN);
   return 1 if ($visible == 1 && $_printed == 0);
   return 2 if ($visible == 1);
   return 0;
}

sub smb {
$return = 0;
print "\nAnalyzing $_[0]\n\n" if $opt_v;
open (SMB,"$TIMEOUT $SMB_TIMEOUT $smbclient \'//$netbios/$_[0]\' -I $ip  -c ls -U \"$account%$password\" -W $thisdomain -Ni 2>/dev/null|");
while (<SMB>) {
   chomp;
   $stuff = $_;
   print "$stuff\n" if $opt_v;
   if (grep(/[0-9][0-9]\:[0-9][0-9]\:[0-9][0-9]/,$stuff))
  {
  $return = 1;
  if (grep(/network.vbs/i,$stuff))
     {
       $service = "netbios-ssn";
       $trustee = "ANY\@$target";
       $trusted = "ANY\@$target";
       $severity = "ht";
       $service_output ="hacker program found";
       $text = "network.vbs found";
       &sara_print();
    }
  }
}
close (SMB);
if (! $opt_r && $return != 0) {
    print "Attempting to write xxx.foo into directory $_[0]\n" if $opt_v; 
    open (SMB, "$TIMEOUT $SMB_TIMEOUT $smbclient \'//$netbios/$_[0]\' -I $ip -c 'lcd /etc;put services $$.foo;ls $$.foo;del $$.foo' -U \"$account%$password\" -N  -W $thisdomain -N 2>/dev/null|");
    while (<SMB>) {
      chomp;
      $stuff .= "$_\n";
    }
    if (grep(/[0-9][0-9]\:[0-9][0-9]\:[0-9][0-9]/,$stuff))
    {
       print "Write successful $_[0]\n" if $opt_v;
       print "$stuff\n" if $opt_v;
       return 2;
    } else {
       print "Write not successful $_[0]\n" if $opt_v;
    }
    return 1;
}

close (SMB);
return $return;
}
