#!/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;
}
}
|