代码之家  ›  专栏  ›  技术社区  ›  bukzor

污染模式perl:通过系统()运行外部程序时保留suid

  •  4
  • bukzor  · 技术社区  · 16 年前

    我正在尝试将功能添加到旧脚本中。脚本是suid,并使用perl-t(污点模式:man perlsec),以获得额外的安全性。我需要添加的特性是用Python实现的。

    我的问题是,我不能说服Perlsec保留suid权限,不管我如何清洗环境和命令行。

    这是令人沮丧的,因为它为其他二进制文件(如/bin/id)保留了suid。是否有/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 回复  |  直到 16 年前
        1
  •  3
  •   Greg Bacon    16 年前

    您需要将真实的用户ID设置为有效的(suid)用户ID。您可能希望对真实的组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函数,并且 SHELLOPTS , BASHOPTS , CDPATH GLOBIGNORE 如果变量出现在环境中,则忽略它们。如果shell的有效用户(组)ID不等于实际用户(组)ID,则 -P 未提供选项,将执行这些操作,并将有效用户ID设置为实际用户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,但可能不会 猛击 _ perl -MConfig -le 'print $Config{sh}' .

    推荐文章