Here is a perl script I wrote that will check your searchpath
to see if you are succeptible to a trojan horse.
execute it by typing
perl trojan.pl
I hope this helps some sites...
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: trojan.pl
# Wrapped by barnett @
grymoire on Mon May 23 11:57:10 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f trojan.pl -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"trojan.pl\"
else
echo shar: Extracting \"trojan.pl\" \(29353 characters\)
sed "s/^X//" >trojan.pl <<'END_OF_trojan.pl'
X##!/bin/sh -- # wish I were -*-Perl-*-
X#eval 'exec perl -S $0 ${1+"$@"}'
X# if !$$;
X#!/bin/perl
X
X# Look for trojan horses...
X
X# A trojan horse looks like a regular program.
X# however, if you execute it, the program may set up a back door to
X# your account, or modify one of your files, etc.
X#
X# This script reports on the different ways someone can drop a trojan hourse
X# in your searchpath.
X#
X# It does not check for set UID or GID programs on your file system,
X# and does not check NFS permissions of directories.
X# It only checks for executables in your searchpath, and reports who and how
X# someone can create a trojan horse.
X#
X# This program also provides a measurement of how vunerable you are to a
X# trojan horse.
X#
X# Bruce Barnett <barnett @
crd .
ge .
com>
X# Copyright 1994 GE
X# All commercial Rights reserved
X#
X# @(#)trojan.pl 1.7 23 May 1994
X#
X# usage:
X#
X# perl trojan.pl [options]
X#
X# where options are any combination of the following
X# -b - brief report. Don't show reasons or executables
X# -a - analyze all files. Normally when a file is world writable,
X# don't check for group or user writable
X# the -a means look at all problems, and not the first
X# -w - just report on world writable problems (no group or user)
X# -g - report on group writable problems ( sets -w, no user)
X# -u - report on world, group and user writable problems (Default)
X# -A - report all files that cause a problem with a group writable
X# permission, not just the first one
X#
X# for debugging purposes, and for more information, try the following options
X# -v - verbose
X# -d - debug
X#
X# Examples
X# trojan.pl - reports world, group and user problems
X# shows reasons for problem
X# trojan.pl -b - reports world, group and user problems
X# Doesn't show reasons
X# trojan.pl -b -a - reports world, group and user problems
X# Doesn't show reasons
X# reports on ALL world, group and user
X# writable problems
X# trojan.pl -b -a -A - reports world, group and user problems
X# Doesn't show reasons
X# reports on ALL world, group and user
X# writable problems
X# Also reports all files that cause group write access
X#
X#
X# trojan.pl -w - reports world writable problems and reasons
X# trojan.pl -g - reports world + group writable problems and reasons
X
X# you probably want to start with trojan.pl -b
X# and fix some of those problems first
X# If you don't understand why it's a problem, omit the -b option
X
X# A malicious cracker will often use your co-workers accounts
X# as a stepping stone to getting root (or bin, daemon, sys, etc.)
X# access. Therefore you have to trust that none of the people who
X# could drop a trojan horse in front of you have had their accounts
X# compromised. If you don't trust them, then don't allow their
X# binaries in your searchpath.
X#
X
X$not_a_csh_script = 0; # this is used in case someone tries
X # "csh trojan.pl"
X# command line OPTIONS
X$all = 0; # print out a more detailed report, (all tests)
X$report_all = 0; # report all files, not just the first one
X$do_world = 1; # print out world writable items
X$do_group = 1; # print out group writable items
X$do_user = 1; # print out user specific info
X$brief = 0; # a short report
X
X$verbose=0; # print more information
X$debug = 0; #
X
X
X
X# VARIABLES
X$dot = 0; # have I seen the "." directory in the path yet?
X$programsafterdot = 0; # how many files were found after the dot?
X$TotalFiles = 0; # total programs or files found in the $PATH directories
X$FilesAfterGroupWritable = 0; # files found after a group writable directory found
X$GroupWritableDirectoryFound = 0; # boolean, true if a group writable diectory found
X$FilesAfterWorldWritable = 0; # files found after a world writable directory found
X$WorldWritableDirectoryFound = 0; # boolean, true if a world writable diectory found
X$world_writable_programs = 0;
X$group_writable_programs = 0;
X$ProgramsInSomeDir = 0;
X
X
X# constants
X
X$SEARCHPATH=1;
X$NOSEARCHPATH=0;
X# PERL variables
X$| = 1; # write to pipes immediately
X
X$revision = "1.7"; # SCCS fills 1.7 in
X$program = "trojan.pl"; # SCCS fills trojan.pl in
Xif ($program =~ /.M./) { # does it match the trojan.pl SCCS string?
X $program = "Trojan"; # yes, fill in the name of the program
X}
Xif ($revision =~ /%/) { # is '%' part of the revision
X $beta = 1; # A beta version
X} else {
X $beta = 0;
X}
X
Xprintf("%s, %s, a study in trust...\n",
X $program,
X $beta ? "Beta release" : "Revision $revision");
X&getswitches();
X&main();
X&report();
Xexit 0;
X
X# --- SUBROUTINES ---
X
Xsub getswitches {
X $FIRST = $[;
X# parse command line arguments
X while ($ARGV[$FIRST] =~ /^-/) {
X# 0 && printf("checkion option %s\n", $ARGV[$FIRST]);
X# verbose
X $ARGV[$FIRST] =~ /^-v/ && ($verbose++,shift(@ARGV),next);
X# debug flag
X $ARGV[$FIRST] =~ /^-d/ && ($debug++,shift(@ARGV),next);
X# all flag
X $ARGV[$FIRST] =~ /^-a/ && ($all++,shift(@ARGV),next);
X# report_all flag
X $ARGV[$FIRST] =~ /^-A/ && ($report_all++,shift(@ARGV),next);
X# brief flag
X $ARGV[$FIRST] =~ /^-b/ && ($brief++,shift(@ARGV),next);
X# -w flag
X $ARGV[$FIRST] =~ /^-w/ && ($do_world++,$do_group = 0, $do_user = 0,shift(@ARGV),next);
X# -g flag
X $ARGV[$FIRST] =~ /^-g/ && ($do_world++,$do_group++, $do_user = 0,shift(@ARGV),next);
X# -u flag
X $ARGV[$FIRST] =~ /^-u/ && ($do_world++,$do_group++, $do_user++,shift(@ARGV),next);
X last;
X
X }
X}
Xsub main {
X &getusers();
X &getgroups();
X &dotrojans();
X}
Xsub dotrojans {
X &checkrootdir();
X @dirs = split(/:/,$ENV{'PATH'});
X foreach $dir (@dirs) {
X $debug && $verbose && printf("%s: \n",$dir);
X $reason = "$dir is in your searchpath";
X if ($dir eq ".") {
X $dot++;
X $dir = `pwd`;
X chop $dir;
X }
X if ( -l $dir) {
X $link = readlink($dir);
X $debug && printf("$dir points to $link\n");
X $reason .= " AND $dir -> $link";
X if ($link !~ /^\// ) {
X # a relative link
X $link = &resolve($dir,$link);
X $reason .= " ($link) ";
X }
X &checkupdir($link,$reason,$SEARCHPATH);
X while ( -l $link ) {
X $oldlink = $link;
X $link = readlink($oldlink); #
X if ($link !~ /^\// ) {
X # a relative link
X $newlink = &resolve($dir,$link);
X $reason .= " ($newlink) ";
X }
X $reason .= "$oldlink -> $link AND";
X &checkupdir($link,$reason,$SEARCHPATH);
X }
X if ( -d $link ) {
X &checkdir($link, $reason);
X &checkupdir($link,$reason,$SEARCHPATH);
X &checkexecsindir($link, $reason);
X
X
X }
X } elsif ( -d $dir ) {
X &checkdir($dir, $reason);
X &checkupdir($dir,$reason,$SEARCHPATH);
X &checkexecsindir($dir, $reason);
X }
X
X }
X}
Xsub checkdir {
X # check the directory itself - it was in the searchpath
X local($dir, $reason) = @_;
X # does the directory exist?
X if ( -l $dir ) {
X printf(STDERR "ERROR: I am testing $dir and it is a link.\n");
X } elsif ( -d $dir ) {
X &testdir($dir,$reason);
X } else {
X printf(STDERR "Missing Directory in searchpath : %s\n", $dir);
X }
X}
Xsub testdir {
X # check the directory itself
X local($dir,$reason) = @_;
X local($hit) = 0;
X # does the directory exist?
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($dir);
X if ($mode & 002) {
X $hit = 1;
X $WorldWritableDirectoryFound = 1;
X &addworld_directory("$reason AND $dir is WORLD writable", $dir);
X }
X # if group writable AND (not world writable or all)
X if ((!$hit || $all) && ($mode & 020)) {
X $hit = 1;
X $GroupWritableDirectoryFound = 1;
X &addgroup_directory($gid,"$reason AND directory $dir is group writable",
X $dir);
X }
X if (!$hit || $all) {
X &adduser($uid,"$reason AND directory $dir writable by owner"); # owner can write to directory
X }
X}
Xsub checkexecsindir {
X # check each executable in the directory
X local($dir, $problem) = @_;
X local($hit);
X local($program);
X local($myproblem);
X $verbose && printf("check execs in dir $dir, reason: $problem\n");
X opendir(D, $dir) || return 0;
X while ($file = readdir(D)) {
X $myproblem = $problem;
X (($file eq ".") || ($file eq "..")) && next;
X $TotalFiles++; # increase number of files found
X $GroupWritableDirectoryFound && $FilesAfterGroupWritable++;
X $WorldWritableDirectoryFound && $FilesAfterWorldWritable++;
X # this is either a file, a directory, or a symbolic link.
X # if a directory, then don't worry about it.
X $program = "$dir/$file";
X # if file, only worry about it if it's executable,
X
X if ( -l $program) {
X # this is a link. Does it point to a file or to a directory?
X # the file in the searchpath is a symbolic link
X # if it points to a directory, then check who owns the directory
X # it is pointing to
X while ( -l $program ) {
X $link = readlink($program);
X $myproblem .= " AND $program -> $link";
X if ($link !~ /^\// ) {
X # a relative link
X $link = &resolve($program,$link);
X $myproblem .= " ($link) ";
X }
X $debug && printf("Problem is now: %s, new program is %s\n",
X $myproblem, $link);
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,; # remove the executable from the path, and check the directory
X $debug && printf("YES: The directory to check now is %s\n",
X $newdir);
X &ProgramUsesDir($newdir);
X &checkupdir($newdir, "$myproblem ", $NOSEARCHPATH);
X $program = $link;
X }
X # no longer a link, it might be a file of directory
X # get the stat on the final file
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($link);
X if (!defined($dev)) {
X # find where it's pointing
X !$brief && printf("Warning: symbolic link %s/%s pointing to missing file: %s\n",
X $dir,$file, $link);
X &checkmissingdir($link,$program);
X } elsif ( -d $link ) {
X # a symbolic link points to a directory.
X # this is only a problem if the directory pointing to is inside
X # a directory that can be modified
X $verbose && printf("\n$dir/$file points to directory $link\n");
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,;
X $verbose && printf("HEY: $link is a directory, and $newdir should be checked\n");
X &checkupdir($newdir, "$dir/$file -> $link AND ",$NOSEARCHPATH);
X } else {
X# printf("$program points to file $link\n");
X $hit = 0;
X
X if ($mode & 0111) { # is this file executable?
X ($hit = ($mode & 002)) && &addworld_file("$dir/$file -> $link AND $link is WORLD writable", "$dir/$file");
X ($hit = ($mode & 020)) && ($all || !$hit) && &addgroup_file($gid,"file $dir/$file -> $link AND $link is group writable", "$dir/$file");
X }
X ($all || !$hit) && &adduser($uid,"file $dir/$file -> $link modifiable by owner"); # owner can modify the target file, and make it executable if it isn't
X # also check by going up the tree of the executable
X $newdir = $link;
X $newdir =~ s,/[^/]+$,,;
X
X $debug && printf("YO: link: $link, newdir: $newdir, calling checkupdir\n");
X &ProgramUsesDir($newdir);
X &checkupdir($newdir, "$dir/$file -> $link AND ",$NOSEARCHPATH); # did I do this twice?
X }
X #
X # if it is a file, check the permission of the file
X #
X } elsif ( -d "$dir/$file" ) { # Not a link, maybe a directory?
X # yes a directory in our search path. Does this mean anything?
X # I guess not. We already go up the directory path
X
X } else { # not a link or directory - a file
X # stat the file
X
X &ProgramUsesDir($dir);
X &testfile("$dir/$file", "$dir/$file executable in path");
X }
X }
X close(D);
X}
X
Xsub testfile {
X local($file,$reason) = @_;
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($file);
X $hit = 0;
X if ($mode & 0111) { # is this file executable?
X# printf("Executable $dir/$file seen\n");
X # increase the number of programs seen
X # if the "." directory has been seen, then
X # this program can be trojanized
X $dot && $programsafterdot++;
X
X if ($mode & 002) {
X # world writable
X $hit = 1;
X &addworld_file("$reason AND $file is WORLD writable", "$file");
X }
X # if group writable AND (not world writable or all)
X if ((!$hit || $all) && ($mode & 020)) {
X $hit = 1;
X &addgroup_file($gid,"$reason AND file $file is group writable", "$file");
X }
X }
X # it doesn't matter if the file is executable or not,
X # the owner can make it executable
X ($all || !$hit) && &adduser($uid,"$reason AND file $file modifiable by owner");
X}
X
X
Xsub adduser {
X local($user,$dir) = @_;
X if (defined($user{$user})) {
X if ($report_all) {
X ($user != "0" && $user != $< ) && printf("user %s can do it because of %s\n", $user, $dir);
X } else {
X $debug && $verbose && printf("user %s can do it because of %s\n", $user, $dir);
X }
X
X # add it to the list
X $user{$user} .= "\n$dir";
X $usercount{$user}++;
X
X } else {
X $user{$user} = $dir;
X $usercount{$user} = 1;
X $verbose && printf("user %s can do it because of %s\n", $user, $dir);
X }
X}
Xsub addgroup_directory {
X local($gid,$reason,$dir) = @_;
X# $GroupWritableDirectoryFound = 1;
X if (!defined($group_writable{$dir})) {
X &addgroup($gid, $reason, $dir);
X $group_writable{$dir} = 1;
X } else {
X $group_writable{$dir}++ ;
X $verbose && printf("Directory '$dir' found again\n");
X }
X}
Xsub addgroup_file {
X local($gid, $reason,$file) = @_;
X $verbose && printf("Group Writable program, gid: %d, file: %s, reasons: %s\n",
X $gid, $file, $reason);
X $group_writable_programs++;
X &addgroup($gid, "File $reason", $file);
X}
Xsub addgroup {
X local($gid,$reason) = @_;
X
X if (defined($group{$gid})) {
X if ($report_all) {
X $all && printf("group %s can do it because of %s\n", $gid, $reason);
X } else {
X $all && $verbose && printf("group %s can do it because of %s\n", $gid, $reason);
X
X }
X # add it to the list
X $group{$gid} .= "\n$reason";
X $groupcount{$gid}++;
X } else {
X $group{$gid} = $reason;
X $groupcount{$gid} = 1;
X $verbose && printf("group %s can do it because of %s\n", $gid, $reason);
X }
X}
Xsub addworld_directory {
X local($reason,$dir) = @_;
X# $WorldWritableDirectoryFound = 1;
X if (!defined($world_writable{$dir})) {
X &addworld($reason);
X $world_writable{$dir} = 1;
X } else {
X $world_writable{$dir}++ ;
X $verbose && printf("Directory '$dir' found again\n");
X }
X}
Xsub addworld_file {
X local($reason,$file) = @_;
X $world_writable_programs++;
X &addworld("File $reason");
X}
Xsub addworld {
X local($reason) = @_;
X $reason =~ s/-\>/\n\t\t->/g;
X $reason =~ s/AND/\n\t\tAND/g;
X # remember world writable directories
X
X !$brief && printf("ANYONE can do it because of %s\n", $reason);
X}
Xsub checkupdir {
X # check the paths leading to the directory
X local($dir, $reason,$onpath) = @_;
X # $onpath is true if this directory is on the searchpath, else false
X if (defined($did_checkup_dir{$dir})) {
X $debug && printf("already checked updir %s\n", $dir);
X return 0; # did it
X } else {
X $did_checkup_dir{$dir} = 1;
X }
X if ($dir eq "." ) {
X die " I should not see a dot in $dir while in checkupdir";
X } elsif ( $dir =~ /^\.\// ) {
X die " I should not see a ./ in $dir while in checkupdir";
X } elsif ( $dir =~ /\/\.\.\// ) {
X die " I should not see a /../ in $dir while in checkupdir";
X } elsif ( $dir =~ /^\.\.\// ) {
X die " I should not see a ../ in $dir while in checkupdir";
X }
X $verbose && printf("checking up dir %s, reason: %s\n",
X $dir, $reason);
X # $dir is the file we are checking, and $reason is why (i.e. "a/b -> /c and")
X# $origfile = $dir;
X while ($dir ne "") {
X #remove the last path
X 1 && $verbose && printf("checkupdir: checking %s\n", $dir);
X if ( -d $dir ) {
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$dir");
X $hit = 0;
X if ($hit = ($mode & 002)) {
X $onpath && ($WorldWritableDirectoryFound = 1);
X &addworld_directory("$reason AND $dir is WORLD writable", $dir);
X }
X if ($hit = ($mode & 020)) {
X $onpath && ($GroupWritableDirectoryFound = 1);
X ($all || !$hit) && &addgroup_directory($gid,"$reason $dir is group writable", $dir);
X }
X ($all || !$hit) && &adduser($uid,"$reason $dir is writable by owner"); # owner can write to directory
X } elsif ( ! -e $dir ) {
X !$brief && printf(STDERR "WARNING: non-existing directory used: $dir\n");
X } else {
X !$brief && printf(STDERR "WARNING: non-directory used: $dir\n");
X }
X $dir =~ s,/[^/]*$,,; # remove last directory from path
X }
X}
Xsub checkrootdir {
X # check the paths leading to the directory
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("/");
X $hit = 0;
X ($hit = ($mode & 002)) && &addworld_directory("'/' is WORLD writable", "/");
X ($hit = ($mode & 020)) && ($all || !$hit) && &addgroup_directory($gid,"Directory '/' is group writable", "/");
X ($all || !$hit) && &adduser($uid,"Directory '/' is writable by owner"); # owner can write to directory
X}
Xsub checkmissingdir {
X # this argument is a file that is missing
X # check to see if each directory up the ladder
X # has permission problems.
X local($file, $where) = @_;
X $origfile = $file;
X while ($file =~ s,/[^/]*$,, && $file ne "") {
X #remove the last path
X $debug && $verbose && printf("checking %s\n", $file);
X if ( -d $file ) {
X ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
X $size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$file");
X $hit = 0;
X ($hit = ($mode & 002)) && &addworld_directory("$where -> $origfile AND $file is WORLD writable", $file);
X ($hit = ($mode & 020)) && ($all || !$hit) && &addgroup_directory($gid,"$where -> $origfile AND $file is group writable", $file);
X ($all || !$hit) && &adduser($uid,"$where -> $origfile AND directory $file is writable by owner"); # owner can write to directory
X }
X }
X}
Xsub report {
X# final report
X if ($debug || $verbose ) {
X printf("Options: ");
X $brief && printf("brief ");
X $all && printf("all ");
X $do_world && printf("do_world ");
X $do_group && printf("do_group ");
X $do_user && printf("do_user ");
X $debug && printf("debug ");
X $verbose && printf("verbose ");
X printf("\n");
X }
X $WorldWritableProgramsByDirectory = 0;
X foreach $d (keys %world_writable) {
X printf("World writable directory %s makes %d files vulnerable\n",
X $d, $ProgramsInDir{$d});
X $WorldWritableProgramsByDirectory += $ProgramsInDir{$d};
X }
X # now for each group
X if ($do_group) {
X $GroupWritableProgramsByDirectory = 0;
X foreach $d (keys %group_writable) {
X printf("Group writable directory %s makes %d files vulnerable\n",
X $d, $ProgramsInDir{$d});
X $GroupWritableProgramsByDirectory += $ProgramsInDir{$d};
X }
X foreach $g (keys %group) {
X $members = $ingroup{$g};
X $name = $gid_to_name{$g};
X $files = $group{$g};
X $files =~ s/\n/\n\t/g;
X $files =~ s/AND/AND\n\t\t/g;
X # truncate all files but the first
X if (!$brief) {
X printf("\nGroup %s can do it %d ways: \n\t%s\n",
X $name, $groupcount{$g}, $files);
X if ($do_user) {
X if (defined($members)) {
X printf("\tmembers of this group are:\n");
X undef(%dummy);
X foreach $m (split(/ /,$members)) {
X if (!defined($dummy{$m})) {
X printf("\t\t%s\n", $m);
X $dummy{$m}=1;
X }
X }
X }
X }
X }
X }
X }
X# now look for each user
X if ($do_user) {
X $NumberOfProgramsOwnerByOtherUsers = 0;
X foreach $u (keys %user) {
X $name = $inuid{$u};
X $files = $user{$u};
X if (!defined($name)) {
X printf("UNKNOWN USER, UID = %d, ", $u);
X } else {
X if (defined($user_to_passwd{$name})) {
X printf("User %s, UID: %d, ",
X $name, $u);
X } elsif ($name =~ / /) {
X # more than one person has this UID...
X printf("Users %s, UID: %d, ",
X $name, $u);
X } else {
X printf("Users %s, UID: %d, ",
X $name, $u);
X }
X }
X if ($u == 0) {
X printf("owns %d file, but you should be able to trust root",
X $usercount{$u});
X } elsif ($u == $>) {
X printf("owns %d file, (but you should be able to trust yourself :-)",
X $usercount{$u});
X } else {
X # truncate all files but the first
X ($file) = split("\n", $files);
X printf("owns %d file%s",
X $usercount{$u},
X ($usercount{$u} == 1) ? "" : "s");
X !$brief && printf(", Example %s",
X $file);
X $NumberOfProgramsOwnerByOtherUsers +=$usercount{$u};
X }
X printf("\n");
X }
X }
X# printf("Number of executable programs: %d\n", $programs);
X printf(" ---- Score (lower percentages are better) ----\n");
X
X $ProgramsInSomeDir = $TotalFiles;
X printf("Number of programs/files in searchpath: %d\n", $ProgramsInSomeDir);
X $do_user && printf("Number of programs writable by others (excluding root and self): %d (%4.2f%%)\n",
X $NumberOfProgramsOwnerByOtherUsers,
X ( $NumberOfProgramsOwnerByOtherUsers/$ProgramsInSomeDir)*100 );
X if ($do_group) {
X printf("Number of group writable programs: %d (%4.2f%%)\n",
X $group_writable_programs,
X ($group_writable_programs/$ProgramsInSomeDir)*100 );
X $debug && printf("Number of executables in group writable directories: %d (%4.2f%%)\n",
X $GroupWritableProgramsByDirectory,
X ( $GroupWritableProgramsByDirectory /$ProgramsInSomeDir)*100 );
X }
X printf("Number of world writable programs: %d (%4.2f%%)\n",
X $world_writable_programs,
X ($world_writable_programs/$ProgramsInSomeDir)*100 );
X $debug && printf("Number of executables in world writable directories: %d (%4.2f%%)\n",
X $WorldWritableProgramsByDirectory,
X ( $WorldWritableProgramsByDirectory /$ProgramsInSomeDir)*100 );
X if ($dot) {
X printf("You have included '.' (current working directory) in your searchpath\n");
X if ($programsafterdot) {
X
X printf("%d files out of %d executable files (%4.2f%%) can be intercepted by a trojan horse depending on your current directory\n",
X $programsafterdot, $ProgramsInSomeDir, ($programsafterdot/$ProgramsInSomeDir)*100.0);
X printf("You are 100%% susceptible to a misspelled program in your current directory (e.g. 'mroe')\n");
X }
X }
X if ($WorldWritableDirectoryFound) {
X printf("%6.2f%% of your files (%d out of %d) may be intercepted because of world writable directories\n",
X ($FilesAfterWorldWritable/$TotalFiles)*100,
X $FilesAfterWorldWritable,
X $TotalFiles);
X }
X if ($GroupWritableDirectoryFound) {
X printf("%6.2f%% of your files (%d out of %d) may be intercepted because of group writable directories\n",
X ($FilesAfterGroupWritable/$TotalFiles)*100,
X $FilesAfterGroupWritable,
X $TotalFiles);
X }
X printf("----\n");
X printf("You may also want to check for set user or set group commands, using..\n");
X printf("\tfind / -type f -perm -4000 -print\n");
X printf("\tfind / -type f -perm -2000 -print\n");
X printf("... but this will take a while.\n");
X printf("You must also trust the systems that provide you with NFS directories\n");
X
X
X
X
X}
X
X
Xsub getusers {
X local($login,$passwd,$uid,$gid);
X# learn about all of the users via the /etc/passwd file
X setpwent(); # # initialize the passwd scan
X while (@list = getpwent) { # fetch the next entry
X ($login,$passwd,$uid,$gid) = @list[0,1,2,3]; #grab the first 4 fields
X if ($debug && (($uid == 2) || ($uid == 3) || ($gid == 2) || ($gid == 3))) {
X printf("User %s, UID: %d, GID: %d\n", $login, $uid, $gid);
X }
X &add_to_group($gid,$login); # list of people who belong to the group
X &add_to_uid($uid,$login); # list of accounts who have the same UID
X
X if (length($passwd) == 13) {
X $user_to_passwd{$login} = $passwd; # do they have a password?
X } else {
X# printf("user %s doesn't have a password\n", $login);
X# printf("length of password %s is %d\n", $passwd, length($passwd));
X }
X }
X endpwent(); # end the scan
X}
Xsub getgroups {
X# learn about all of the groups via the /etc/group file
X local($login,$passwd,$uid,$members);
X setgrent(); # # initialize the group scan
X while (@list = getgrent()) { # fetch the next entry
X ($login,$passwd,$gid,$members) = @list[0,1,2,3]; #grab the first 4 fields
X if ($debug && (($gid == 2) || ($gid == 3))) {
X printf("Group %s, GID: %d\n", $login, $gid);
X }
X if (!defined($gid_to_name{$gid})) {
X $gid_to_name{$gid} = $login;
X } else {
X # group already defined
X if ($gid_to_name{$gid} ne $login) {
X $verbose && printf("Group ID #%d, name: %s, also called %s - ignoring new name\n",
X $gid, $gid_to_name{$gid}, $login);
X }
X }
X
X # each of the members should be added to the group list
X foreach $m (split(/ /,$members)) {
X 0 && $debug && printf("adding %s to group %s(%d)\n",
X $m, $login, $gid);
X &add_to_group($gid,$m); # list of people who belong to the group
X }
X if (length($passwd) == 13) {
X# $group_to_passwd{$login} = $passwd; # do they have a password?
X } else {
X# printf("group %s doesn't have a password\n", $login);
X# printf("length of password %s is %d\n", $passwd, length($passwd));
X }
X }
X endgrent(); # end the scan
X
X}
Xsub add_to_group {
X local ($gid,$login) = @_; # list of people who belong to the group
X # add user $login to group $gid
X if (defined($ingroup{$gid})) {
X $ingroup{$gid} .= " $login";
X } else {
X $ingroup{$gid} = "$login";
X }
X}
Xsub add_to_uid {
X local($uid,$login) = @_; # list of accounts who have the same UID
X# create map of UID -> USERS
X if (defined($inuid{$uid})) {
X # check to see if name is in the list
X $found = 0;
X foreach $u (split(/ /,$inuid{$uid})) {
X ($u eq $login) && $found++;
X }
X (!$found) && $inuid{$uid} .= " $login";
X } else {
X $inuid{$uid} = "$login";
X }
X# check for map of user -<> UIDs.
X#; if more than one, error
X if (defined($inuser{$login})) {
X if ($uid != $inuser{$login}) {
X
X $inuser{$login} .= " $uid";
X printf(STDERR " User %s (UID: %d) has duplicate UID's : %s\n", $login, $uid, $inuser{$login});
X } else {
X # saw this user twice, but the UID was the same
X }
X } else {
X $inuser{$login} = "$uid";
X }
X
X}
Xsub resolve {
X local($current,$link) = @_;
X local($newlink,$newcurrent);
X # we are faces with a relative symbolic link
X # that is, the firct character of $link is NOT a '/'
X # examples
X # /a/b -> c/d - same as /a/c/d
X # /a/b/c -> ../d - same as /a/d
X # /a/b/c -> ./d - same as /a/c/d
X # /a/b/c -> ./../d - same as /a/d
X # /a/b/c -> ../../d - same as /d
X # /a/b/c -> . - same as /a/b
X
X $newlink = "";
X if ($current =~ /^\.\.\// ) {
X die "ERROR : left side can't start with ../";
X } elsif ($current =~ /^\.\// ) {
X die "ERROR : left side can't start with ./";
X } elsif ($current =~ /^[^\/]/ ) {
X die "ERROR : left side can't start with non-/";
X }
X
X if ($link =~ /^\.\.\//) { # ../
X #resolve relative link -> ../
X
X # remove last two items on current
X $newcurrent = $current;
X # change /a/b/c/d to /a/b
X $newcurrent =~ s,[^\/]+\/[^\/]+$,,;
X
X # remove ../ from ../xxxx
X $newlink = $link;
X $newlink =~ s,^\.\.\/,,;
X
X # combine two pieces
X $newlink = "$newcurrent$newlink";
X
X # there may still be a ../ in there
X # change x/v/../ to nothing
X $newlink =~ s,[^\/]+\/\.\.,,g;
X
X $debug && printf("RESOLVE: $current -> $link becomes $newlink\n");
X } elsif ($link eq "." ) { #
X #resolve relative link -> .
X # remove last part of path
X $newcurrent = $current;
X # change /a/b/c/d to /a/b/c
X $newcurrent =~ s,\/[^\/]+$,,; # /a/b/c -> /a/b
X
X $newlink = "$newcurrent";
X $debug && printf("RESOLVE: $current -> $link becomes $newlink\n");
X } elsif ($link =~ /^\.\//) { # starts with ./
X #resolve relative link -> ./usr
X # remove last part of path
X $newcurrent = $current;
X # change /a/b/c/d to /a/b/c
X $newcurrent =~ s,\/[^\/]+$,,;
X
X # remove ./ from ./xxxx
X $newlink = $link;
X $newlink =~ s,^\.\/,,; # ./xyz -> xyz
X
X # combine two pieces
X $newlink = "$newcurrent/$newlink";
X
X $debug && printf("RESOLVE: $current -> $link becomes $newlink\n");
X } elsif ($link =~ /^[^\/]/) { # starts with aaa/
X #resolve relative link -> usr/
X # remove last part of path
X $newcurrent = $current;
X # change /a/b/c/d to /a/b/c
X $newcurrent =~ s,\/[^\/]+$,,; # /a/b/c -> /a/b
X
X $newlink = $link;
X
X # combine two pieces
X $newlink = "$newcurrent/$newlink";
X $debug && printf("RESOLVE: $current -> $link becomes $newlink\n");
X } else {
X printf(STDERR "$current/$link becomes ?????\n");
X }
X $newlink =~ s,\/\/,\/,g;
X
X# John P. Rouillard <rouilj @
terminus .
cs .
umb .
edu> suggested:
X $newlink =~ s,^/\./,\/,g; # change /./ to /
X
X if ($newlink !~ /^\//) {
X die "return value from RESOLVE ($newlink) invalid";
X } elsif ($newlink =~ /\/\.\.\//) {
X die "return value from RESOLVE ($newlink) invalid";
X } elsif ($newlink =~ /\/\.\//) {
X die "return value from RESOLVE ($newlink) invalid";
X }
X return $newlink;
X}
Xsub ProgramUsesDir {
X# this procedure is called once for each program.
X# this input is a directory
X local($dir) = @_;
X if ( ! -d $dir ) {
X if (! -e $dir ) {
X # file doesn't exist
X return;
X } else {
X die "Directory $dir NOT a directory, serious bug, aborting";
X }
X }
X $ProgramsInSomeDir++;
X if (defined($ProgramsInDir{$dir})) {
X $ProgramsInDir{$dir}++;
X } else {
X $ProgramsInDir{$dir} = 1;
X }
X
X# now do the same thing with each step up the directory tree
X while ($dir ne "/") {
X $dir =~ s,\/[^\/]+$,,;
X if ($dir eq "") {
X $dir = "/";
X }
X if (defined($ProgramsInDir{$dir})) {
X $ProgramsInDir{$dir}++;
X } else {
X $ProgramsInDir{$dir} = 1;
X }
X
X }
X
X}
END_OF_trojan.pl
if test 29353 -ne `wc -c <trojan.pl`; then
echo shar: \"trojan.pl\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
|
|