考虑到CGI
脚本Perl
和taint mode中的以下内容,我无法理解以下内容。
tail /etc/httpd/logs/error_log /usr/local/share/perl5/Net/DNS/Dig.pm line 906 (#1) (F) You tried to do something that the tainting mechanism didn't like. The tainting mechanism is turned on when you're running setuid or setgid, or when you specify -T to turn it on explicitly. The tainting mechanism labels all data that's derived directly or indirectly from the user, who is considered to be unworthy of your trust. If any such data is used in a "dangerous" operation, you get this error. See perlsec for more information. [Mon Jan 6 16:24:21 2014] dig.cgi: Insecure dependency in eval while running with -T switch at /usr/local/share/perl5/Net/DNS/Dig.pm line 906.
代码:
#!/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
,模块似乎无法使用无法修改的变量,所以我现在处于亏损状态。
如何让这件事通过污点检查?
答案 0 :(得分:2)
$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第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->Dump
生成的经过验证的代码将$tobj
设置为$self
(Deepcopy(1)
)的深层副本,并正确设置了自引用(Purity(1)
)和基本漂亮的打印(Indent(1)
)。
根据我发现的&Net::DNS::Dig::to_text
,很明显问题是$self
内至少有一个受污染的项目。因此,您可以通过直接的方式进一步调试问题:在脚本中构造$dig
对象后,检查其中的哪些项目已被污染。您可以使用print Data::Dumper::Dump($dig);
将整个结构转储到标准输出,这与使用过的代码大致相同,并使用&Scalar::Util::tainted
检查可疑项目。
我不知道这使得Net::DNS::Dig
在污点模式下工作了多远。我不使用它,我只是好奇,想找出问题所在。当你设法解决问题时,我会在此阶段离开它,让其他人继续调试问题。
答案 1 :(得分:1)
作为对这个问题的解决方案,如果有人在未来遇到它,那确实是我使用的模块导致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;
感谢您在这件事上给我提供的评论,以及我所教授的任何其他资源。