[ http://www.rootshell.com/ ]

                   From emoc@vortex.misterweb.com Fri Aug  7 11:42:42 1998
                   Date: Thu, 6 Aug 1998 14:39:48 -0500 (EST)
                   From: Matthew George <emoc@vortex.misterweb.com>
                   To: submission@rootshell.com

                   #!/usr/bin/perl -w

                   ## sysmon.pl
                   ## Author: emoc <emoc@misterweb.com>

                   ## This script, run on a regular (daily) basis, keeps tabs
                   ## on root accounts and set[ug]id root files. Output includes:
                   ##  list of all uid/gid 0 (or 131072) accounts
                   ##  list of all set[ug]id 0 files
                   ##  root accounts that have been added, changed, or deleted since last run
                   ##  set[ug]id 0 files that have been added, changed (incl. size), or deleted since last run

                   ## By default, it will mail the results to root.
                   ## It would be best to invoke it from root's cron using:
                   ## 0 0 * * * /path/to/sysmon.pl


                   ########################
                   ### User Definitions ###
                   ########################

                   # [0/1] Do we have a shadow password setup (assumes /etc/shadow)?
                   # Enabling this means that the script will process information from /etc/shadow.
                   # It will enable the script to see if passwords on root accounts have changed,
                   # but if you don't want it touching the shadow file, just set to 0
                   $USE_SHADOW = 1;

                   # [0/1] This will disable the mail to root and simply display the
                   # results of the script to STDOUT
                   $NOMAIL = 0;


                   ############
                   ### Code ###
                   ############


                   # open /etc/passwd (and /etc/shadow if defined above) and pull all root acct info
                   open(PWD, "/etc/passwd") || die("open /etc/passwd: $!");
                   while (<PWD>) {

                           # also checks for uid / gid 131072, which can be interpreted as 0
                           if ((/.*:0:.*/) || (/.*:131072:.*/)) {
                                   chomp;
                                   $data = $_;
                                   s/:.*//;
                                   $login = $_;
                   #D cpinfo -> npinfo
                                   $npinfo{$login} = $data;

                                   if ($USE_SHADOW) {

                                           open(SHADOW, "/etc/shadow") || die("open /etc/shadow: $!");
                                           while (<SHADOW>) {

                                                   if (/$login/) {
                                                           chomp;
                                                           $nsinfo{$login} = $_;
                   #D cpinfo -> npinfo on rt of =
                                                           $npinfo{$login} = $npinfo{$login} . "\n" . $_
                                                   }
                                           }
                                           close(SHADOW) || die("close /etc/shadow: $!");

                   #D              } else {
                   #D                      $npinfo{$login} = $cpinfo{$login}
                                   }
                           }
                   }
                   close(PWD) || die("close /etc/passwd: $!");


                   ### END Acct. checks
                   ### BEGIN set[ug]id 0 checks

                   sub checkperms {

                           if ( -u $file) {
                                   $uid = (stat($file))[4];
                                   if ($uid == 0) {
                                           $nsulist{$file} = `ls -dl $file`;
                                           chomp($nsulist{$file});
                                           return 1;
                                   }

                           } elsif ( -g $file) {
                                   $gid = (stat($file))[5];
                                   if ($gid == 0) {
                                           $nsglist{$file} = `ls -dl $file`;
                                           chomp($nsglist{$file});
                                           return 1;
                                   }
                           }
                           
                           return 0;
                   }


                   $dirlist[0] = "";
                   foreach $dir (@dirlist) {

                           foreach $file (<${dir}/*>) {
                                   # turn all those nasty little quotes and ticks in filenames into literals that sh can parse a bit more cleanly
                                   $file =~ s/\'/\\\'/;
                                   $file =~ s/\"/\\\"/;
                                   $file =~ s/\`/\\\`/;

                                   # directories (excluding proc) that aren't links
                                   if (( -d $file) && ($file ne "/proc") && (! -l $file)) {
                                           checkperms();
                                           push(@dirlist, $file);

                                   # set[ug]id files that aren't links
                                   } elsif ((( -u $file) || ( -g $file)) && (! -l $file)) {
                                           checkperms();
                                   }
                           }

                           # same with everything that starts w/ a .
                           foreach $file (<${dir}/.*>) {

                                   # make sure we aren't looking at */. or */.. as well
                                   if (( -d $file) && (! -l $file) && (! (($file =~ m#/\.$#) || ($file =~ m#/(\.)\1$#)))) {
                                           checkperms();
                                           push(@dirlist, $file);

                                   } elsif ((( -u $file) || ( -g $file)) && ((! -l $file) && (! (($file =~ m#/\.$#) || ($file =~ m#/(\.)\1$#))))) {
                                           checkperms();
                                   }
                           }
                   }


                   if (! $NOMAIL) {
                           open(MAIL, "|mail root") || die("open mail: $!");
                           select(MAIL);
                   }


                   dbmopen(%pinfo, "/var/log/pinfo", 0600) || die("dbmopen pinfo: $!");

                   print("="x20, "\n");
                   print("Root accounts which have been added or changed since last check:\n\n");
                   foreach $login (sort keys %npinfo) {
                           if (! $pinfo{$login}) {
                                   print("$login (old):\n", "NON-EXISTANT\n\n");
                                   print("$login (new):\n", "$npinfo{$login}\n\n");
                                   $pinfo{$login} = $npinfo{$login};

                           } elsif ($npinfo{$login} ne $pinfo{$login}) {
                                   print("$login (old):\n");
                                   print("$pinfo{$login}\n\n");
                                   print("$login (new):\n");
                                   print("$npinfo{$login}\n\n");
                                   $pinfo{$login} = $npinfo{$login};
                           }
                   }


                   print("="x20, "\n");
                   print("Root accounts which have been deleted since last check:\n");
                   foreach $login (sort keys %pinfo) {
                           if (! $npinfo{$login}) {
                                   print("$login:\n");
                                   print("$pinfo{$login}\n\n");
                                   delete($pinfo{$login});
                           }
                   }
                   print("\n");


                   dbmclose(%pinfo);
                   dbmopen(%sulist, "/var/log/sulist", 0600);

                   print("="x20, "\n");
                   print("Files that have changed or had setuid privileges added since last check:\n");
                   foreach $file (sort keys %nsulist) {
                           if (! $sulist{$file}) {
                                   print("$file (old):\n");
                                   print("NON-EXISTANT\n");
                                   print("$file (new):\n");
                                   print($nsulist{$file}, "\n\n");
                                   $sulist{$file} = $nsulist{$file};

                           } elsif ($nsulist{$file} ne $sulist{$file}) {
                                   print("$file (old):\n");
                                   print($sulist{$file}, "\n");
                                   print("$file (new):\n");
                                   print($nsulist{$file}, "\n\n");
                                   $sulist{$file} = $nsulist{$file};
                           }
                   }
                   print("\n");


                   print("="x20, "\n");
                   print("Files that have been moved, renamed, deleted, or had setuid privileges dropped:\n");
                   foreach $file (sort keys %sulist) {
                           if (! $nsulist{$file}) {
                                   print("$file (old):\n");
                                   print($sulist{$file}, "\n");
                                   print("$file (new):\n");
                                   if ( -e $file) {
                                           $nv = `ls -dl $file`;
                                           chomp($nv);
                                           print($nv, "\n\n")
                                   } else {
                                           print("MOVED, RENAMED, OR DELETED\n\n");
                                   }
                                   delete($sulist{$file});
                           }
                   }
                   print("\n");

                   dbmclose(%sulist);
                   dbmopen(%sglist, "/var/log/sglist", 0600);

                   print("="x20, "\n");
                   print("Files that have changed or had setgid privileges added since last check:\n");
                   foreach $file (sort keys %nsglist) {
                           if (! $sglist{$file}) {
                                   print("$file (old):\n");
                                   print("NON-EXISTANT\n");
                                   print("$file (new):\n");
                                   print($nsglist{$file}, "\n\n");
                                   $sglist{$file} = $nsglist{$file};

                           } elsif ($nsglist{$file} ne $sglist{$file}) {
                                   print("$file (old):\n");
                                   print($sglist{$file}, "\n");
                                   print("$file (new):\n");
                                   print($nsglist{$file}, "\n\n");
                                   $sglist{$file} = $nsglist{$file};
                           }
                   }
                   print("\n");

                   print("="x20, "\n");
                   print("Files that have been moved, renamed, deleted, or had setgid privileges dropped:\n");
                   foreach $file (sort keys %sglist) {
                           if (! $nsglist{$file}) {
                                   print("$file (old):\n");
                                   print($sglist{$file}, "\n");
                                   print("$file (new):\n");
                                   if ( -e $file) {
                                           $nv = `ls -dl $file`;
                                           chomp($nv);
                                           print($nv, "\n\n")
                                   } else {
                                           print("MOVED, RENAMED, OR DELETED\n\n");
                                   }
                                   delete($sglist{$file});
                           }
                   }
                   print("\n");

                   dbmclose(%sglist);


                   print("="x20, "\n");
                   open(DF, "df|");
                   print(<DF>, "\n");
                   close(DF);


                   print("="x20, "\n");
                   print("Users with either uid or gid 0 or 131072:\n\n");
                   #D cpinfo -> npinfo
                   foreach (sort keys %npinfo) {
                           if ($USE_SHADOW) {
                   #D cpinfo -> npinfo
                                   print($_, "\n", $npinfo{$_}, "\n", $nsinfo{$_}, "\n\n")
                           } else {
                   #D cpinfo -> npinfo
                                   print($_, "\n", $npinfo{$_}, "\n\n")
                           }
                   }


                   print("="x20, "\n");
                   print("setuid root files:\n");
                   foreach (sort keys %nsulist) {
                           print("$nsulist{$_}\n");
                   }
                   print("\n");

                   print("="x20, "\n");
                   print("setgid root files that aren\'t setuid:\n");
                   foreach (sort keys %nsglist) {
                           print("$nsglist{$_}\n");
                   }
                   print("\n");


                   if (! $NOMAIL) {
                           close(MAIL);
                   }