如何作为nobody用户在CGI程序中运行shell命令?

时间:2011-04-28 04:28:40

标签: perl security unix cgi

我想在CGI程序中运行shell命令(用Perl编写)。我的程序没有root权限。它像没人一样运行。我想使用这段代码:

use strict;
system <<'EEE';
awk '{a[$1]+=$2;b[$1]+=$3}END{for(i in a)print i, a[i], b[i]|"sort -nk 3"}' s.txt
EEE

我可以从命令行使用perl成功运行我的代码,但不能作为CGI程序运行。

5 个答案:

答案 0 :(得分:1)

根据您问题中的代码,至少有四种失败的可能性。

  1. nobody用户无权执行您的程序。
  2. 您问题中的Perl代码没有shebang(#!)行。您正在尝试运行awk,因此我假设您正在运行某种形式的Unix。如果您的代码缺少此行,那么您的操作系统将不知道如何运行您的程序。
  3. 文件s.txt不在执行程序的工作目录中,或者无人用户无法读取。
  4. 无论出于何种原因,都无法通过执行程序环境的PATH访问awk
  5. 要快速诊断此类低级别问题,请尝试将所有错误输出显示在浏览器中。一种方法是在代码中的shebang行之后添加以下内容。

    BEGIN {
        print "Content-type: text/plain\n\n";
        open STDERR, ">&", \*STDOUT or print "$0: dup: $!";
    }
    

    输出将呈现为纯文本而不是HTML,但这是查看程序输出的临时措施。通过将其包装在BEGIN块中,代码在解析后立即执行。重定向STDERR意味着您的浏览器也会获得写入标准输出的任何内容。

    另一种方法是使用CGI::Carp模块。

    use CGI::Carp 'fatalsToBrowser';
    

    这样,错误会发送到浏览器以及Web服务器的错误日志。

    如果您仍然看到来自服务器的500系列错误,则问题发生在较低级别:可能是某些启动失败perl。去检查服务器的错误日志。程序执行后,您可以删除错误输出的临时重定向。

    最后,我建议您将程序更改为

    #! /usr/bin/perl -T
    
    BEGIN { print "Content-type: text/plain\n\n"; }
    
    use strict;
    use warnings;
    
    $ENV{PATH} = "/bin:/usr/bin";
    
    my $input = "/path/to/your/s.txt";
    
    my $buckets = <<'EOProgram'
    { a[$1] += $2; b[$1] += $3 }
    
    END { for (i in a) print i, a[i], b[i] }
    EOProgram
    
    open STDIN, "-|", "awk", $buckets, $input or die "$0: open: $!";
    exec "sort", "-nk", 3                     or die "$0: exec: $!";
    

    -T开关启用名为taint mode的安全数据流分析,可防止您对系统操作(例如openexec等)使用未经过抽取的输入攻击者(或提供意外输入的良性用户)可能会损害您的系统。您应该始终将-T添加到CGI程序以及代表其他用户运行的任何其他代码。

    鉴于你的awk程序的性质,text / plain的内容类型似乎是合理的。尽快输出。

    启用污点模式后,请明确说明PATH环境变量的值。如果您坚持使用程序继承的任何不受信任的PATH,则尝试运行外部程序将失败。

    指出输入的完整路径。这将消除意外。

    使用openexec的多参数形式消除了shell及其参数解析。 (为了完整性,system也有类似的多参数形式。)是的,这样写它可能意味着being a little more deliberate(比如打破参数并自己设置管道),但它也是避免令人讨厌的惊喜。

答案 1 :(得分:0)

我确信允许nobody运行shell命令。问题是nobody无权打开文件s.txt。将所有人的读取权限添加到s.txt,并向每个目录中的所有人添加执行权限,直至s.txt

答案 2 :(得分:0)

我建议找出awk的完整限定路径并直接指定它。可能没有启动httpd的人在$ ENV {PATH}中有一条非常小的路径。显示我猜的$ ENV {PATH}将显示此信息。

这是一件好事,我不会修改路径,只是指定路径/​​ usr / bin / awk或者不是。

如果你有shell访问权限并且它有效,请输入'which awk'来查找它。

答案 3 :(得分:0)

  

我可以成功运行我的代码   perl文件但不在cgi文件中。

您在运行什么Web服务器?例如,apache需要打印CGI标题,即print "Content-type: text/plain; charset=utf-8\n\n"

use CGI;
my $q = CGI->new();
print $q->header('text/html');

(见CGI

Apache会在日志(error.log)中提及有关“脚本标题过早结束”的内容,如我所说的那样。

答案 4 :(得分:0)

你可以直接进行内联,而不必分叉到另一个进程......

if ( open my $fh, '<', 's.txt' ) {
    my %data;
    while (<$fh>) {
        my ($c1,$c2,$c3) = split;
        $data{a}{$c1} += $c2;
        $data{b}{$c1} += $c3;
    }
    foreach ( sort { $data{b}{$a} <=> $data{b}{$b} } keys %{ $data{b} } ) {
        print "$_ $data{a}{$_} $data{b}{$_}\n";
    }

} else {
    warn "Unable to open s.txt: $!\n";
}