taint en mode perl:préserver suid lors de l'exécution de programme externe via system()

StackOverflow https://stackoverflow.com/questions/3313855

Question

Je suis en train d'ajouter une fonctionnalité à un héritage de script.Le script est suid, et utilise perl -T (souillure mode:l'homme perlsec), pour plus de sécurité.La fonctionnalité que je dois ajouter est implémenté en Python.

Mon problème est que je ne peux pas convaincre perlsec pour préserver les permissions les permissions, peu importe combien j'ai de blanchir de l'environnement et de la ma des lignes de commande.

Ce qui est frustrant, car elle préserve la suid pour les autres fichiers binaires (comme /bin/id).Est-il un sans-papiers cas particulier pour /usr/bin/perl?Cela semble peu probable.

Est-ce quelqu'un connais un moyen de faire ce travail?(Que-est:Nous n'avons pas les ressources nécessaires pour réorganiser tout ça.)


Solution: (comme par @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")');

Donne les résultats souhaités!


Voici un coupe-bas version de mon script, qui montre toujours mon problème.

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

Et voici le résultat:

$ 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
Était-ce utile?

La solution

Vous devez définir votre véritable nom d'utilisateur de l'effectif (suid-ed) une.Vous voulez probablement faire la même chose pour votre real id de groupe:

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

Exemple d'exécution:

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

$ ./suid.pl 
nobody
gbacon
nobody

Ce que vous voyez est documenté bash comportement:

-p

Tourner sur le mode privilégié.Dans ce mode, le $BASH_ENV et $ENV les fichiers ne sont pas traitées, shell fonctions ne sont pas héritées de l'environnement, et de la SHELLOPTS, BASHOPTS, CDPATH et GLOBIGNORE les variables, si elles apparaissent dans l'environnement, sont ignorés.Si le shell est lancé avec l'utilisateur (le groupe) id n'est pas égale à l'utilisateur réel (groupe) id, et le -p l'option n'est pas fournie, ces mesures sont prises et l'uid effectif est défini à l'identificateur d'utilisateur réel.Si l' -p option est fournie au démarrage, l'id utilisateur n'est pas réinitialisé.La désactivation de cette option provoque l'efficacité de l'utilisateur et id de groupe à définir le réel de l'utilisateur et id de groupe.

Cela signifie que vous pourriez aussi

#! /usr/bin/perl -T

use warnings;
use strict;

$ENV{PATH} = "/bin:/usr/bin";

system "/bin/bash", "-p", "-c", "id -un";

pour obtenir

nobody

Rappelons que passer plusieurs arguments pour system contourne la coquille.Un seul argument n'est aller à la coquille, mais probablement pas bash—chercher à la sortie de perl -MConfig -le 'print $Config{sh}'.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top