Taint-mode perl: save suid when starting an external program through the system ()

I am trying to add a function to an obsolete script. The script is suid and uses perl -T (taint mode: man perlsec) for added security. The function I need to add is implemented in Python.

My problem is that I cannot convince perlsec to retain suid rights no matter how much I clean up the environment and my command lines.

This is frustrating since it saves suid for other binaries (such as / bin / id). Is there an undocumented special case for / usr / bin / perl? This seems unlikely.

Does anyone know a way to make this work? ( As-is : we don’t have the resources to reverse engineer it all.)


Solution: (according to @gbacon)

# use the -p option to bash system('/bin/bash', '-p', '-c', '/usr/bin/id -un'); # or set real user and group ids $< = $>; $( = $); system('/usr/bin/python', '-c', 'import os; os.system("/usr/bin/id -un")'); 

Gives the desired results!


Here is a cut out version of my script that still shows my problem.

 #!/usr/bin/perl -T ## This is an SUID script: man perlsec %ENV = ( "PATH" => "" ); ##### PERLSEC HELPERS ##### sub tainted (@) { # Prevent errors, stringifying local(@_, $@ , $^W) = @_; #let eval catch the DIE signal $SIG{__DIE__} = ''; my $retval = not eval { join("",@_), kill 0; 1 }; $SIG{__DIE__} = 'myexit'; return $retval } sub show_taint { foreach (@_) { my $arg = $_; #prevent "read-only variable" nonsense chomp $arg; if ( tainted($arg) ) { print "TAINT:'$arg'"; } else { print "ok:'$arg'"; } print ", "; } print "\n"; } ### END PERLSEC HELPERS ### # Are we SUID ? man perlsec my $uid = `/usr/bin/id --user` ; chomp $uid; my $reluser = "dt-pdrel"; my $reluid = `/usr/bin/id --user $reluser 2> /dev/null`; chomp $reluid; if ( $uid ne $reluid ) { # what ? we are not anymore SUID ? somebody must do a chmod u+s $current_script print STDERR "chmod 4555 $myname\n"; exit(14); } # comment this line if you don't want to autoflush after every print $| = 1; # now, we're safe, single & SUID # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # BEGIN of main code itself print "\nENVIRON UNDER BASH:\n"; run('/bin/bash', '-c', '/bin/env'); print "\nTAINT DEMO:\n"; print "\@ARGV: "; show_taint(@ARGV); print "\%ENV: "; show_taint(values %ENV); print "`cat`: "; show_taint(`/bin/cat /etc/host.conf`); print "\nworks:\n"; run('/usr/bin/id', '-un'); run('/usr/bin/id -un'); print "\ndoesn't work:\n"; run('/bin/bash', '-c', '/usr/bin/id -un'); run('/bin/bash', '-c', '/bin/date >> /home/dt-pdrel/date'); run('/bin/date >> /home/dt-pdrel/date'); run('/usr/bin/python', '-c', 'import os; os.system("/usr/bin/id -un")'); run('/usr/bin/python', '-c', 'import os; os.system("/usr/bin/id -un")'); sub run { my @cmd = @_; print "\tCMD: '@cmd'\n"; print "\tSEC: "; show_taint(@cmd); print "\tOUT: "; system @cmd ; print "\n"; } 

And here is the conclusion:

 $ id -un bukzor $ ls -l /proj/test/test.pl -rwsr-xr-x 1 testrel asic 1976 Jul 22 14:34 /proj/test/test.pl* $ /proj/test/test.pl foo bar ENVIRON UNDER BASH: CMD: '/bin/bash -c /bin/env' SEC: ok:'/bin/bash', ok:'-c', ok:'/bin/env', OUT: PATH= PWD=/proj/test2/bukzor/test_dir/ SHLVL=1 _=/bin/env TAINT DEMO: @ARGV: TAINT:'foo', TAINT:'bar', %ENV: ok:'', `cat`: TAINT:'order hosts,bind', works: CMD: '/usr/bin/id -un' SEC: ok:'/usr/bin/id', ok:'-un', OUT: testrel CMD: '/usr/bin/id -un' SEC: ok:'/usr/bin/id -un', OUT: testrel doesn't work: CMD: '/bin/bash -c /usr/bin/id -un' SEC: ok:'/bin/bash', ok:'-c', ok:'/usr/bin/id -un', OUT: bukzor CMD: '/bin/bash -c /bin/date >> /home/testrel/date' SEC: ok:'/bin/bash', ok:'-c', ok:'/bin/date >> /home/testrel/date', OUT: /bin/bash: /home/testrel/date: Permission denied CMD: '/bin/date >> /home/testrel/date' SEC: ok:'/bin/date >> /home/testrel/date', OUT: sh: /home/testrel/date: Permission denied CMD: '/usr/bin/python -c import os; os.system("/usr/bin/id -un")' SEC: ok:'/usr/bin/python', ok:'-c', ok:'import os; os.system("/usr/bin/id -un")', OUT: bukzor CMD: '/usr/bin/python -c import os; os.system("/usr/bin/id -un")' SEC: ok:'/usr/bin/python', ok:'-c', ok:'import os; os.system("/usr/bin/id -un")', OUT: bukzor 
+4
source share
1 answer

You need to set the real user id to effective (suad-ed). You probably want to do the same for your real group id:

 #! /usr/bin/perl -T use warnings; use strict; $ENV{PATH} = "/bin:/usr/bin"; system "id -un"; system "/bin/bash", "-c", "id -un"; # set real user and group ids $< = $>; $( = $); system "/bin/bash", "-c", "id -un"; 

Run Example:

  $ ls -l suid.pl
 -rwsr-sr-x 1 nobody nogroup 177 2010-07-22 20:33 suid.pl

 $ ./suid.pl 
 nobody
 gbacon
 nobody 

What you see is documented as bash behavior:

-p

Enable privileged mode. In this mode, the $BASH_ENV and $ENV files are not processed, shell functions are not inherited from the environment, and the variables SHELLOPTS , BASHOPTS , CDPATH and GLOBIGNORE , if they appear in the environment, are ignored. If the shell starts with an effective user (group) identifier that is not equal to the identifier of the real user (group), and the -p parameter is not specified, these actions are performed and the real user identifier is set to the real user identifier. If the -p option is provided at startup, effective user id is not reset. Disabling this option causes the effective user and group identifiers to be set to real user and group identifiers.

That means you can also

 #! /usr/bin/perl -T use warnings; use strict; $ENV{PATH} = "/bin:/usr/bin"; system "/bin/bash", "-p", "-c", "id -un"; 

To obtain

  nobody 

Recall that passing multiple arguments to system bypasses the shell. One argument goes to the shell, but probably not bash -look on the output perl -MConfig -le 'print $Config{sh}' .

+3
source

Source: https://habr.com/ru/post/1316603/


All Articles