Well, since I won't be able to reboot some of the machines for the foreseeable future, I just went ahead and banged this thing out. Only minor testing has been done thus far, and it doesn't handle all the potential special characters that a filename could possibly have, but it does handle spaces and dollar signs.

Maybe this will help someone else someday.

#! /usr/bin/perl # ==================================================================== +===== # sudo-copy - perl script to allow semi-secure file copying ability +for # sudo. Giving pretty much any copy rights to an sudoer makes it triv +ial # for the sudoer to escalate to full root permissions. # # This script attempts to make it difficult to carry out a copy operat +ion # exploit to full root access. # ==================================================================== +===== # Task Description: # De-obfuscate the source and destination files # No recursive or directory copies # No symbolic links allowed in the source or destination # Check /etc/sudo-copy.conf file for valid target list # If all rules pass, allow the copy to happen. # ==================================================================== +===== # Written by Scott L. Miller # # Born on date: 05/08/2008 use strict; use warnings; use File::Basename; use IO::Tee; use Getopt::Std; use vars qw($opt_h $LOG); getopts('h'); sub usage { print <<ENDUSAGE; $0 [-h] <source> <destination> Allow restricted copy operations to suduoers. Why? Unrestricted copy operations make it trivial for any sudoer to escalate to full root permissions. The more restricted the copy operations are, the harder it is to exploit. Output goes both to STDOUT and /var/log/sudo-copy.log file. Options: -h -h or no parameters will print this message. ENDUSAGE exit 1; } my $argc = scalar(@ARGV); usage() if $opt_h || not $argc; die "Need one source and one destination\n" if ($argc != 2); my $logfile = "/var/log/sudo-copy.log"; $|=1; my ($starttime, $startdate) = GetTime(); $LOG = IO::Tee->new(">> $logfile", \*STDOUT) or die "Error during IO::Tee->new\n $!\n"; print $LOG "========================================================== +=======\n"; print $LOG "Started @ $startdate $starttime\n"; sub get_actual_path { my ($path) = @_; if(chdir "$path") { # CDing into a directory and then calling /bin/pwd sho +uld normalize whatever # strange input might be given to us by the user. my $actual_dir = `/bin/pwd`; chomp $actual_dir; return $actual_dir; } else { print $LOG "Can't cd into <$path>: $!\n"; print $LOG "Copy failed.\n"; die; } } my ($src, $dst) = @ARGV; my ($srcFileName, $srcPath, $srcFileExt, $dstFileName, $dstPath, $dstF +ileExt); ($srcFileName, $srcPath, $srcFileExt)=fileparse($src); ($dstFileName, $dstPath, $dstFileExt)=fileparse($dst); $srcPath = get_actual_path($srcPath); $dstPath = get_actual_path($dstPath); $src = $srcPath.'/'.$srcFileName.$srcFileExt; $dst = $dstPath.'/'.$dstFileName.$dstFileExt; if($src =~ /\$/) { $src =~ s/\$/\\\$/g; #escape the dollar signs } if($dst =~ /\$/) { $dst =~ s/\$/\\\$/g; #escape the dollar signs } foreach ($src,$dst) { lstat($_); if ( -l _ ) { print $LOG "Error: symbolic links not allowed\ +n"; print $LOG "Copy failed.\n"; die; } if ( -d _ ) { print $LOG "Error: directory copies not allowe +d\n"; print $LOG "Copy failed.\n"; die; } if ( -e _ && ! -f _ ) { print $LOG "Error: file is not a plain file\n" +; print $LOG "Copy failed.\n"; die; } } if(check_valid_destination($dst)) { my ($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($dst); dosystem("cp -f \"$src\" \"$dst\""); if($uid ne '') { dosystem("/bin/chown $uid.$gid \"$dst\""); chmod $mode, $dst; } print $LOG "Copy complete.\n"; } else { print $LOG "Copy not allowed\n"; } my ($endtime, $enddate) = GetTime(); print $LOG "Finished @ $enddate $endtime\n"; exit; sub check_valid_destination { my $fname = $_[0]; my $cfgfile = '/etc/sudo-copy.conf'; open (CFGFILE, $cfgfile) || die "Couldn't open \"$cfgfile\"\n $!\n"; while(<CFGFILE>) { s/(^\s+)//; #remove indentation if any if(/^$/) { next; } #ignore blank lines if(/^#/) { next; } #ignore comments chomp; if (eval "\'$fname\' =~ $_") { close CFGFILE; return 1; } } close CFGFILE; return 0; } sub dosystem { my $rc = system(@_) & 0xFFFF; if ($rc == 0) { return; } if ($rc == 0xff00 ) { print $LOG "Command [@_] failed: $!\n"; exit 0; } if ($rc > 0x80) { $rc >>= 8; print $LOG "Command [@_] ran with exit code $rc\n"; return; } if ($rc & 0x80) { printf $LOG "Core dumped from signal %d\n", $rc & 0x7 +F; exit 0; } else { printf $LOG "Interrupted by signal %d\n", $rc & 0x7F; exit 0; } print $LOG "Should never be able to get here\n"; } sub numerically { no warnings; $a <=> $b; } sub GetTime { my ($sec,$min,$hr,$mday,$mon,$yr,$wday,$yday,$isdst) = localti +me(time()); my $date = sprintf("%02d/%02d/%04d",$mday,$mon+1,$yr+1900); my $time = sprintf("%02d:%02d:%02d",$hr,$min,$sec); return ($date, $time); }
Example /etc/sudo-copy.conf
# A list of perl regexes of files that sudo-copy is allowed # to copy to (the destination) #test entry m#/tmp/test.*# #ntp.conf should be relatively safe m#/etc/ntp\.conf# #ldap.conf could be exploited if an attacker created a new ldap instan +ce m#/etc/ldap\.conf# #resolv.conf could be exploited in many subtle ways (new ldap instance +, yum, etc) m#/etc/resolv\.conf# #yum could be exploited if an attacker created a new yum repository m#/etc/yum\.conf# m#/etc/yum\.repos\.d/.*#
-Scott

In reply to Re: semi secure sudo script to allow restricted copy ability by 5mi11er
in thread semi secure sudo script to allow restricted copy ability by 5mi11er

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.