Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

monitor suid and world writtable files

by Anonymous Monk
on Jul 18, 2005 at 14:44 UTC ( [id://475780]=sourcecode: print w/replies, xml ) Need Help??
Category: utility scripts
Author/Contact Info
Description: need to write a script to scan system for new suid and world-writtable files, send email about the scan result if discover one or more. It skips /home and NFS mounted directories. the NFS mount skipping part is for solaris only.
#!/usr/bin/perl -w
#

# scan world writable and suid files
# must be root to run this script
# The NFS mount point checking works for solaris ONLY. 


use File::Find;
use Getopt::Long;
use strict;

my $email = 'your@email.com'; # sent email about scan result

my $suid_file = '/var/audit/YU.suid.log'; 
my $ww_file   = '/var/audit/YU.world-writtable.log';  

my @suid_list    =();
my @ww_list      =();
my @dirs_to_skip = ();  # dirs to skip
my @fndlist = ('/');    # top dirs to search from
chomp(my $host = `hostname`);

# add NFS mount to our ignore list. FOR SOLARIS ONLY
chomp(@dirs_to_skip = `mount | grep remote | cut -d' ' f1`);
# add /home to our ignore list
push @dirs_to_skip, ('/home','/proc');

my $OPTIONS = <<"_OPTIONS";

Usage: $0 [-c|-d] 

  -h,         display this helpscreen and exit
  -v,         show scan result
  -c,         create the base list for suid/world-writtable, saved in 
+suid.list and ww.list
  -d,         scan and diff the current scan result with a base list

_OPTIONS


my ($opt_help,$opt_verbose,$opt_create_base,$opt_diff);

GetOptions(
  'h!'     => \$opt_help,
  'v!'     => \$opt_verbose,
  'c!'     => \$opt_create_base,
  'd!'     => \$opt_diff,
) or usage('Invalid Option');

######################

if ($opt_create_base) {
    scan_suid_ww();
    create_base();
} elsif ($opt_diff) {
    if (!(-e $suid_file) or !(-e $ww_file)) {
        print "no base file to compare, generating base file\n" if $op
+t_verbose;
        scan_suid_ww();
        create_base();
    } else {
        scan_suid_ww();
        my(@suid_diff,@ww_diff);
        my $email_msg = '';
        
        if (@suid_list) {
            @suid_diff = make_diff($suid_file,@suid_list);
            $email_msg .= "\n###### Found ". scalar(@suid_diff)." new 
+suid files ######\n\n";
            $email_msg .= join "\n",@suid_diff;
        }
        if (@ww_list) {
            @ww_diff = make_diff($ww_file,@ww_list);
            $email_msg .= "\n\n###### Found ". scalar(@ww_diff) ." new
+ world-writtable files ######\n\n";
            $email_msg .= join "\n",@ww_diff;
        }
        # send email if find new suid or ww files
        if (@suid_diff or @ww_diff) {
            print $email_msg if $opt_verbose;
            `/usr/bin/echo "$email_msg" |
                   /usr/bin/mailx -s "suid and ww scan difference resu
+lt on $host" $email`;
            # update the base with the new findings.
            create_base();
        }
    }
} else {
    usage("Missing Argument: -c or -d");
}

sub create_base {
    open F,">$suid_file" or die $!;
    print F join "\n", sort @suid_list;
    close F;
    open F,">$ww_file" or die $!;
    print F join "\n", sort @ww_list;
    close F;
}

sub make_diff {
    my ($file,@list) = @_;
    open F,$file or die "open $file error: $!\n";
    my @oldlist = <F>;
    close F;
    chomp @oldlist;
    my %oldlist;
    @oldlist{@oldlist}=1;
    return grep { !exists $oldlist{$_} } @list;
}

sub usage {
    die @_, $OPTIONS;
}

########## helper function ###########

sub scan_suid_ww {
    find( \&_find_suid_ww, @fndlist );
    print "no suid file found\n" if (!@suid_list && $opt_verbose);
    print "no world-writtable file found\n" if (!@ww_list && $opt_verb
+ose);
}

sub _find_suid_ww {

   for (@dirs_to_skip) {
        if ($File::Find::name eq $_) {
            print "skipping $_ \n" if $opt_verbose;
            $File::Find::prune = 1;
            return;
        }
    }
                                               
    my ( $dev, $ino, $mode, $nlink, $uid, $gid );

    if ( ( ( $dev, $ino, $mode, $nlink, $uid, $gid ) = lstat($_) ))
    {
        if ( ( ( $mode & 02 ) == 02 ) && -f && !-l ) {
            push( @ww_list, $File::Find::name );
        }
        push( @suid_list, $File::Find::name ) if -u;
    }
}
Replies are listed 'Best First'.
THKs 4 Ur good example!
by chanio (Priest) on Jul 18, 2005 at 19:25 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://475780]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (2)
As of 2024-11-03 02:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    chatterbot is...






    Results (13 votes). Check out past polls.