taint-mode perl:通过system()运行外部程序时保留suid

时间:2010-07-22 21:59:38

标签: perl bash taint suexec suid

我正在尝试为旧脚本添加功能。该脚本是suid,并使用perl -T(污点模式:man perlsec),以提高安全性。我需要添加的功能是用Python实现的。

我的问题是,无论我多少次清洗环境和命令行,我都无法说服perlsec保留suid权限。

这很令人沮丧,因为它保留了其他二进制文件的suid(例如/ bin / id)。 / usr / bin / perl是否有未记录的特殊情况?这似乎不太可能。

有没有人知道如何使这项工作? (按原样:我们没有足够的资源来重新构建这一切。)


解决方案:(根据@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")');

给出了预期的结果!


这是我的脚本的简化版本,它仍然显示我的问题。

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

这是输出:

$ 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

1 个答案:

答案 0 :(得分:3)

您需要将真实用户ID设置为有效(suid-ed)。您可能希望对您的真实组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";

示例运行:

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

$ ./suid.pl 
nobody
gbacon
nobody

您所看到的内容记录为bash行为:

  

-p

     

启用特权模式。在此模式下,不处理$BASH_ENV$ENV文件,不从环境继承shell函数,SHELLOPTSBASHOPTSCDPATHGLOBIGNORE个变量(如果它们出现在环境中)将被忽略。如果以有效用户(组)id不等于真实用户(组)id启动shell,并且未提供-p选项,则执行这些操作并将有效用户ID设置为实际用户身份。如果在启动时提供了-p选项,则不会重置有效用户ID。关闭此选项会导致有效的用户和组ID设置为真实用户和组ID。

这意味着你也可以

#! /usr/bin/perl -T

use warnings;
use strict;

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

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

获取

nobody

回想一下,将多个参数传递给system会绕过shell。单个参数确实转到shell,但可能不是bash - 查看perl -MConfig -le 'print $Config{sh}'的输出。