【问题标题】:Perl taint mode with domain name input for CGI resulting in “Insecure dependency in eval”Perl 污点模式与 CGI 的域名输入导致“评估中的不安全依赖”
【发布时间】:2014-01-06 22:39:09
【问题描述】:

CGI 脚本中使用Perltaint mode 给出以下内容,我无法通过以下内容。

尾 /etc/httpd/logs/error_log /usr/local/share/perl5/Net/DNS/Dig.pm 第 906 行(#1) (F) 你试图做一些污染机制不喜欢的事情。 当您运行 setuid 或 setgid,或者当您指定 -T 以显式打开它时。这 污染机制标记所有直接或间接派生的数据 来自被认为不值得您信任的用户。如果有的话 此类数据用于“危险”操作,您会收到此错误。看 perlsec 了解更多信息。 [2014 年 1 月 6 日星期一 16:24:21] dig.cgi:在 /usr/local/share/perl5/Net/DNS/Dig.pm 第 906 行使用 -T 开关运行时,评估中的依赖关系不安全。

代码:

#!/usr/bin/perl -wT
use warnings;
use strict;
use IO::Socket::INET;
use Net::DNS::Dig;
use CGI;

$ENV{"PATH"} = ""; # Latest attempted fix

my $q      = CGI->new;
my $domain = $q->param('domain');

if ( $domain =~ /(^\w+)\.(\w+\.?\w+\.?\w+)$/ ) {
    $domain = "$1\.$2";
}
else {
    warn("TAINTED DATA SENT BY $ENV{'REMOTE_ADDR'}: $domain: $!");
    $domain = "";    # successful match did not occur
}

my $dig = new Net::DNS::Dig(
    Timeout   => 15,        # default
    Class     => 'IN',      # default
    PeerAddr  => $domain,
    PeerPort  => 53,        # default
    Proto     => 'UDP',     # default
    Recursion => 1,         # default
);

my @result = $dig->for( $domain, 'NS' )->to_text->rdata();
@result = sort @result;
print @result;

我通常使用Data::Validate::Domain 来检查“有效”域名,但无法以不会发生受污染变量错误的方式部署它。

我读到,为了清除变量,您必须通过带有捕获组的regex 将其传递,然后加入捕获组以对其进行清理。所以我部署了$domain =~ /(^\w+)\.(\w+\.?\w+\.?\w+)$/。如图here 所示,它不是最好的regex,目的是去除域名的污点并覆盖所有可能的域,但它满足我的需求。不幸的是,我的脚本仍然在产生受污染的失败,我不知道是怎么回事。

Regexp-Common 没有提供域 regex,并且模块似乎无法使用无污染的变量,所以我现在不知所措。

如何让这个东西通过污点检查?

【问题讨论】:

  • 我不认为问题出在你的代码中(你做了 untaint $domain),该模块可能无法在 taint 模式下工作。
  • Scalar::Util qw(tainted) 证明我的变量没有被污染,所以它肯定是某种形式的模块。感谢您的帮助和新的(对我而言)模块@Palec

标签: regex perl cgi


【解决方案1】:

$domain 没有被污染

我确认您的$domain 没有受到污染。在我看来,这是您使用的唯一可能被污染的变量。

perl -T <(cat <<'EOF'
use Scalar::Util qw(tainted);
sub p_t($) {
    if (tainted $_[0]) {
        print "Tainted\n";
    } else {
        print "Not tainted\n";
    }
}
my $domain = shift;
p_t($domain);
if ($domain =~ /(^\w+)\.(\w+\.?\w+\.?\w+)$/) {
    $domain = "$1\.$2";
} else {
    warn("$domain\n");
    $domain = "";
}
p_t($domain);
EOF
) abc.def

打印出来

Tainted
Not tainted

Net::DNS::Dig 的作用

参见Net::DNS::Dig 906 行。这是to_text 方法的开始。

sub to_text {
    my $self = shift;
    my $d = Data::Dumper->new([$self],['tobj']);
    $d->Purity(1)->Deepcopy(1)->Indent(1);
    my $tobj;
    eval $d->Dump; # line 906
    …

new 定义我知道$self 只是包含来自new 参数和其他几个填充在构造函数中的值的hashref。 $d-&gt;Dump 生成的评估代码将 $tobj 设置为 $self (Deepcopy(1)) 的深层副本,并正确设置了自引用 (Purity(1)) 和基本的漂亮打印 (Indent(1))。

问题出在哪里,如何调试

根据我对&amp;Net::DNS::Dig::to_text 的发现,很明显问题出在$self 中至少有一个被污染的项目。所以你有一个直接的方法来进一步调试你的问题:在你的脚本中构造 $dig 对象之后,检查它的哪些项目被污染了。您可以使用print Data::Dumper::Dump($dig); 将整个结构转储到标准输出,这与评估代码大致相同,并使用&amp;Scalar::Util::tainted 检查可疑项目。

我不知道这离使Net::DNS::Dig 在污点模式下工作有多远。我不使用它,我只是好奇并想找出问题所在。由于您设法以其他方式解决了您的问题,因此我将其保留在此阶段,允许其他人继续调试该问题。

【讨论】:

    【解决方案2】:

    作为对这个问题的解决方案,如果将来有人遇到它,确实是我使用的模块导致taint 检查失败。在CGI 环境中教我一个关于信任模块的重要课程。我切换到Net::DNS,因为我认为它不会遇到这个问题,而且肯定不会。下面提供了我的代码以供参考,以防有人想要完成我打算做的相同事情:在其自己的区域文件中找到为域定义的名称服务器。

    #!/usr/bin/perl -wT
    use warnings;
    use strict;
    use IO::Socket::INET;
    use Net::DNS;
    use CGI;
    
    $ENV{"PATH"} = ""; // Latest attempted fix
    
    my $q      = CGI->new;
    my $domain = $q->param('domain');
    my @result;
    
    if ( $domain =~ /(^\w+)\.(\w+\.?\w+\.?\w+)$/ ) {
        $domain = "$1\.$2";
    }
    else {
        warn("TAINTED DATA SENT BY $ENV{'REMOTE_ADDR'}: $domain: $!");
        $domain = "";    # successful match did not occur
    }
    
    my $ip = inet_ntoa(inet_aton($domain));
    
    my $res   = Net::DNS::Resolver->new(
        nameservers => [($ip)],
    );
                            my $query = $res->query($domain, "NS");
    
                            if ($query) {
                                    foreach my $rr (grep { $_->type eq 'NS' } $query->answer) {
                                    push(@result, $rr->nsdname);
                                    }
                            }
                            else {
                                    warn "query failed: ", $res->errorstring, "\n";
                            }
    
    @result = sort @result;
    print @result;
    

    感谢 cmets 在这件事上为我提供帮助,因此,与我遇到的任何其他资源相比,他们提供的教学更多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-26
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多