# This is essientially a management shell script for remote install and update of machines from retina scans # Run as administrator in a command prompt and follow steps # Retina Remediate Setup: ! must be saved in HTML format # Group by vulnerability # Sort machines by IP address # Short vulnerabilities by risk # Options checked, Page breaks, detailed audit status, job metrics and sev code. # Known Issues: Running from windows xp as admin, some issues with windows 7 compatibility # This is with lack of remote access to \\computer\admin$ share that psexec uses use Win32; use File::stat; use Switch; use Term::ReadKey; use Net::SMTP; use DateTime; use POSIX qw(strftime); system("cls"); # Variable Declaration section # DECLARE THE LOCATIONS of retina, Psexec, and packages ----------------------------------------------------------- $retina = '-----'; $psexec='-----'; $packages='-----'; @FILES; $FILE = (); $TD=''; $TABLE=''; $td_num=0; $ta_num=0; @AT; # Table Array @ATD; # TD Array @Vln; # Vunerabilities @VList; # List of computers with Vulnerabilities $Exclude; # List of excluded computers $currentV; # Current Vln $key; @RetinaVul; # Retna tables divided by vulnerability @VLocation; # DEFINE LOCATIONS note: 64 bit alternatives must come directly after their 32 counterparts (JDK JRE) ----------- # RETINA VULNERABILITY FLAG -- PACKAGE LOCATION -- FOLDER NAME -- FILE NAME -- QUIET FLAGS -- COMPUTER LIST (empty) # --------- 0 ------------- -- ------ 1 ------- -- ---- 2 ---- -- --- 3 --- -- ---- 4 ---- -- -------- 5 ---------- @FirstList= ( ["None","None","None","None"], ["Windows", $packages, "Windows", "WU.*nolog.bat"], ["JDK", $packages, "Java", "jdk-.*i586.exe", "/qn JAVAUPDATE=1 REBOOT=Suppress EULA=1"], ["JDK x64", $packages, "Java", "jdk-.*x64.exe", "/qn JAVAUPDATE=1 REBOOT=Suppress EULA=1"], ["JRE", $packages, "Java", "jre-.*i586.exe", "/qn JAVAUPDATE=1 REBOOT=Suppress EULA=1"], ["JRE x64", $packages, "Java", "jre-.*x64.exe", "/qn JAVAUPDATE=1 REBOOT=Suppress EULA=1"], ["Firefox", $packages, "Firefox", "Firefox.*.exe", "-ms"], ["Thunderbird", $packages, "Thunderbird", "Thunderbird.*.exe", "-ms"], ["Adobe Flash Mozilla", $packages, "Adobe", "install_flash_player.exe", "-install"], ["Adobe Flash IE", $packages, "Adobe", "install_flash_player_ax.exe", "-install"], ["Adobe Reader", $packages, "Acrobat", "AdbeRdr.*_en_US.exe", "/sAll"] #, ); # Programs to be manually updates list ---------------------------------------------------------------------------- @SecondaryList = ( ["QuickTime", $packages, "QuickTime", "QuickTimeInstaller.exe", "/qn"], ["VLC", $packages, "", "none", "none"], ["Ghostscript", $packages, "", "none", "none"], ["Opera", $packages, "", "none", "none"], ["Notepad++", $packages, "", "none", "none"], ["IrfanView", $packages, "", "none", "none"], ["Critical Patch Updates", $packages, "", "none", "none"], ["PHP", $packages, "", "none", "none"], ["PostgreSQL", $packages, "", "none", "none"], ["Google Chrome", $packages, "", "none", "none"] ); # List of excluded computers -------------------------------------------------------------------------------------- @Excluded = ("-----"); # Command selection print('1-email full list now, 2-push files, 3-view full list, 4-Advanced Push:'); ReadMode('cbreak'); $mode = ReadKey(0); if( ($mode == 3) || ($mode == 1) ) { push (@VLocation, @FirstList); push (@VLocation, @SecondaryList); } else { push (@VLocation, @FirstList); } if($mode == 4) { print("\n1-Use Exlude List 2-No Exluded:"); $key = ReadKey(0); if($key == 2) { @Excluded=""; } } ReadMode('normal'); if( ($mode == 2) || ($mode == 1) || ( ($mode == 4 ) && ($key == 1) ) ) { foreach my $e (@Excluded) { if( $Exclude ) { $Exclude= $Exclude.",$e "; } else { $Exclude = "$e "; } } print ("\n\nExcluding: ".$Exclude."\n"); } print("\n\n"); # CHANGE ITEM [1] TO FULL LOCATION OF FILE & SET VLN TO VULNERABILITY NAME my $n=0; foreach (@VLocation) { @Vln[$n] = @VLocation[$n]->[0]; unless ($n == 0) {@VLocation[$n]->[1] = @VLocation[$n]->[1]."\\".@VLocation[$n]->[2]."\\".FindVer(@VLocation[$n]->[3], @VLocation[$n]->[1]."\\".@VLocation[$n]->[2]) || die "!! Package issue"; } # print(@VLocation[$n]->[1]."\n"); $n++; } # Imput retina file dest, otherwise use Default print("\n---------------------------------------------------\n\n"); print("Imput retina file destination (Enter for Default Current):"); chomp($FILE = <STDIN>); if ($FILE eq "") { $FILE = FindVer("Remediation.*.htm", "$retina"); $FILE = "$retina\\$FILE"; print("Using current file: $FILE\n"); } else { $FILE =~ tr/"//d; } print("\n--------------------Summary------------------------\n\n"); # Open file for parsing open(MYINPUTFILE, "$FILE"); my $contents = do { local $/; <MYINPUTFILE> }; # Seperates retina file vunerabilities into tables s flag ignores \n for . @RetinaVul = split( /<BR style=\"PAGE-BREAK-AFTER: always\" clear=all>.*?<\/STYLE>/s, $contents); # Incriments through each retina vunerability for (my $R=0; $R < scalar @RetinaVul; $R++) { my $currentV; # Current vulnerability refrence as number # Splits tables into sub tables @temp = split( /<TD.*?>+/s, @RetinaVul[$R]); @RetinaVul[$R] = @temp; for (my $T=0; $T < scalar @temp; $T++) { my $break = 0; # Cleanup <*> and remove \n and extra " " while (grep { s/<.*?>//g } @temp[$T] ) { @temp[$T] =~ s/<.*?>//smg; } @temp[$T] =~ s/\s+/ /smg; # Write value back into array @RetinaVul[$R]->[$T] = @temp[$T]; # Searches for vulnerability unless ($currentV) { if ($T == 1) { # Flags java on overall description if ( grep { m/Windows - JRE/ } @RetinaVul[$R]->[$T] ) { $currentV = FindVln("JRE"); } if ( grep { m/Windows\s-\sJDK/ } @RetinaVul[$R]->[$T] ) { $currentV = FindVln("JDK"); } # Flags adobe on overall description if ( grep { m/Adobe Flash\s.*\s-\sIE/ } @RetinaVul[$R]->[$T] ) { $currentV = FindVln("Adobe Flash IE"); } if ( grep { m/Adobe Flash.*Mozilla/ } @RetinaVul[$R]->[$T] ) { $currentV = FindVln("Adobe Flash Mozilla"); } if ( grep { m/Windows\s-\sReader/ } @RetinaVul[$R]->[$T] ) { $currentV = FindVln("Adobe Reader"); } } # If no java flag, look for how to fix, and next vulnerability if (!$currentV) { if ( grep { /How To Fix:/ } @RetinaVul[$R]->[$T-1] ) { for (my $m; $m < scalar @VLocation; $m++) { my $retinaName = @VLocation[$m]->[0]; # print("!!$retinaName!!"); if ( grep { m/$retinaName/s } @RetinaVul[$R]->[$T] ) { $currentV = $m; } } } } } if ($currentV) { if ( grep { /(Firefox|Thunderbird)/ } @VLocation[$currentV]->[0] ) { if(($T+5)<scalar @temp) { $break = 1; # print(@temp[$T+4]." !!!".@temp[$T-1]."!!!\n"); # <STDIN>; if ( grep { /Tested.*\n.*Value:/m } @temp[$T+4] ) { if ( grep { /CMP,A,WB,Firefox_NOTEQ/m } @temp[$T+5] ) { $break = 0; $currentV = 6; } } if ( grep { m/Tested.*\n.*Value:/m } @temp[$T+4] ) { if ( grep { /CMP,A,WB,Thunderbird_NOTEQ/m } @temp[$T+5] ) { $break = 0; $currentV = 7; } } } } } # If vunerability, look for computer names # --- If vulnerability ----- On our local network ------------------------ Windows machines only -------- if ( ($currentV) && (grep { /^129\.65\.183\.\d{1,3}/ } @temp[$T-2] ) && (grep { m/^Windows/ } @temp[$T]) && ($break == 0) ) { # ----------------- IF NAME ALREADY EXSITS IN LIST -------------- IF LOWERCASE NOT NETBIOS NAME --------- IF NOT AN EXCLUDED MACHINE --------- unless ( ( grep { m/@temp[$T-1]/ } @VLocation[$currentV]->[5] ) || ( grep { m/[a-z]/ } @temp[$T-1] ) || ( grep { m/@temp[$T-1]/ } $Exclude ) || !($currentV)) { # IF 64 BIT JAVA SEND TO NEXT LIST if ( ( grep { m/[x|X]64/ } @temp[$T] ) && (grep { m/JDK|JRE/ } @VLocation[$currentV]->[0] ) ) { if (!@VLocation[$currentV+1]->[5]) { @VLocation[$currentV+1]->[5]= "@temp[$T-1]"; } else { @VLocation[$currentV+1]->[5]= ("@VLocation[$currentV+1]->[5],@temp[$T-1]"); } } else { if (!@VLocation[$currentV]->[5]) { @VLocation[$currentV]->[5]= "@temp[$T-1]"; } else { @VLocation[$currentV]->[5]= ("@VLocation[$currentV]->[5],@temp[$T-1]"); } } } } } # Test purpose prints # print("-----------------------------------------\n"); # print("@VLocation[$currentV]->[0]"); } close(MYINPUTFILE); # Take list data and process # 1 - email list 2 - push files 3 - print/save full list 4 - Advanced mode (individual vulnerability push) switch ($mode) { case "1" { # EMAIL my $email = "After hours tonight, systems will be running applicable updates on the following machines. " . "Please make sure your work is saved and machines remain powered on. If there is an issue " . "with this list please inform ---- systems, and If your computer is on the Java JRE list " . "please remember to uninstall old versions after the new one is installed. If you computer " . "needs windows updates please do a shutdown install at the earliest convenience . Thank you. \n\n"; print ("Email: \n$email\n\nEnter to accept, text to append:"); chomp (my $input = <STDIN>); if ($input) { $email = $email . "Special Note: ". $input ."\n\n"; } for (my $C=2; $C < scalar @FirstList; $C++) { # Cleanup whitespace computer list my $computers = @VLocation[$C]->[5]; $computers =~ s/\s//smg; $computers =~ s/,/, /mg; $email=$email."@VLocation[$C]->[0]\n $computers\n"; } $email=$email."\n\n Things to be manually updated: \n\n"; for (my $E = (scalar @FirstList); $E < scalar @VLocation; $E++) { # Cleanup whitespace computer list my $computers = @VLocation[$E]->[5]; $computers =~ s/\s//smg; $computers =~ s/,/, /mg; $email=$email."@VLocation[$E]->[0]\n $computers\n"; } EmailCADRC($email, '-----@-----.edu'); #mail TO } case ["2","4"] { # PUSH FILES my @pushlist; my $input; # Print for check for (my $C=1; $C < scalar @VLocation; $C++) { # Cleanup whitespace computer list my $computers = @VLocation[$C]->[5]; $computers =~ s/\s//smg; # Split computers into list of 10 @pushlist = computerArray($computers); print("\n@VLocation[$C]->[0]\n"); foreach my $temp (@pushlist) { print(" $temp\n"); } } if ($mode == 2) { # Final check before push print("Press Enter to continue, q to quit, number for min delay:"); $input = <STDIN>; chomp($input); if ( grep { m/\d/ } $input ) { $input = $input * 60; # convert seconds to min my $dt = SleepMin($input); print("\n\nProcess will run at ".$dt->hour.":".$dt->min." on ".$dt->mdy."\n"); sleep $input; $input = ""; } } if (!$input) { for (my $C=1; $C < scalar @VLocation; $C++) { my $key; if ($mode == 4) { ReadMode('cbreak'); print("\n\n1-Push @VLocation[$C]->[0], 2-Skip:"); $key = ReadKey(0); ReadMode('normal'); } if ( ($mode == 2) || ($key == 1) ) { # Cleanup whitespace computer list my $computers = @VLocation[$C]->[5]; $computers =~ s/\s//smg; # Split computers into list of 10 & Push @pushlist = computerArray($computers); # print("\n@VLocation[$C]->[0]\n"); foreach my $temp (@pushlist) { # print(" $temp\n"); system("$psexec","\\\\$temp",'-s','-c','-v','-n','360',qq("@VLocation[$C]->[1]"),@VLocation[$C]->[4]); } } } } break; } case "3" { ## Print/Save for (my $C=1; $C < scalar @VLocation; $C++) { # Cleanup whitespace computer list my $computers = @VLocation[$C]->[5]; $computers =~ s/\s//smg; # Split computers into list of 10 my @comp = computerArray($computers); print("\n@VLocation[$C]->[0]\n"); foreach $temp (@comp) { print(" $temp\n"); } } # print('Save to file?(y/n):'); <STDIN>; } } # -------------------------- END MAIN ------------------------------------ # Split computer list into groups of 10 for psexec execution sub computerArray { my $string = $_[0]; my @array; my $listcount = 0; my $arraycount = 0; my @divided = split( /,/s, $string); foreach my $d (@divided) { if ($listcount==10) { $arraycount++; $listcount=0; } if (@array[$arraycount]) { @array[$arraycount] = "@array[$arraycount],$d"; } else { @array[$arraycount] = "$d";} $listcount++; } return @array; } # Find which vulnerability sub FindVln { for (my $n; $n < scalar @VLocation; $n++) { if ( @VLocation[$n]->[0] eq $_[0]) { return $n; $n = scalar @VLocation; } } } # Find the version of program and location for push, warn if multiple and use reciently modified sub FindVer { # nm is name, dr is directory, dh is temp database pointer my $currentRetina = 0; my $dh; my $n; my $t; my @F; my $nm = $_[0]; my $dr = $_[1]; # print("!! $nm, !! $dr"); opendir($dh, "$dr") || die "FindVer DR Error"; @F = grep { /^$nm/ } readdir($dh); # print("$nm ".scalar @F."\n"); if( (scalar @F > 1) && !($nm eq "Remediation.*.htm") ) { print("!! - Duplicate versions of $nm,\n "); } foreach ($n=0; $n < scalar @F; $n++) { open FILE, "$dr\\@F[$n]" or die "FindVer Incriment Error"; $t=stat(FILE)->ctime; close FILE; # Find most Current File if ($t > $currentRetina) { $currentRetina=$t; $nm = @F[$n]; } } if( (scalar @F > 1) && !(grep { m/Remediation/ig } $nm ) ) { print("Using file: $nm\n"); } # print("Using file: $nm\n"); closedir $dh; return $nm; } # Time Delay sub SleepMin { my $dt = DateTime->now; my $epoch_time = $dt->epoch; $epoch_time = $epoch_time + $_[0]; $dt = DateTime->from_epoch( epoch => $epoch_time ); $dt->set_time_zone('America/Los_Angeles') ; return $dt; } # Email CADRC sub EmailCADRC { my $body = $_[0]; my $to = $_[1]; $smtp = Net::SMTP->new('---.---.---.---'); # connect to an SMTP server $smtp->mail( '-----@-----.edu' ); # use the sender's address here $smtp->to($to); # recipient's address $smtp->data(); # Start the mail # Send the header. $smtp->datasend("To: All -----\n"); $smtp->datasend("Subject: Updates Tonight\n"); $smtp->datasend("From: -----\n"); $smtp->datasend("\n"); # Send the body. $smtp->datasend("$body\n"); $smtp->dataend(); # Finish sending the mail $smtp->quit; # Close the SMTP connection }