Challenge
Bill Gates wrote a Perl script that grants access to the company records; it has a security flaw that lets everyone in. Fix the flaw.
Bill Gates 写了个 Perl 脚本,用来校验访问者有没有权限读取公司记录;这段脚本存在安全缺陷,任何人都能拿到记录。要求把缺陷修掉。
#!/usr/bin/perlchomp ( my $User = `/usr/bin/whoami` ) ;print "Checking your access level...\n" ;if ( $User == 'BillGates' ) { print "Authorized! Here are the company records:\n" . `cat /home/BillGates/CompanyRecords.db` ; die ( "Closing...\n" ) ;}die ( "You're not authorized!\n" ) ;Solution
脚本的逻辑很短:用反引号执行 /usr/bin/whoami 拿到当前用户名存进 $User,然后只有一个 if 决定是否读取 /home/BillGates/CompanyRecords.db。要修好缺陷,改动点必然落在这个比较上;其它行(chomp、print、die)都只是输出,不参与授权判断。
Perl 有两套比较运算符,不能混用:
==、!=、<、>:数值比较,会先把两侧操作数转成数字;eq、ne、lt、gt:字符串比较,逐字符对比。
脚本用的是 $User == 'BillGates'。两侧都是字符串,却在走数值比较。用 Perl 直接复现这个语义:
#!/usr/bin/perl# Local reproduction of the ExtBasic 8 flaw (run against our own Perl, no# network). A non-privileged user name stands in for the whoami output.use strict;use warnings;
my $User = "some_user"; # what `/usr/bin/whoami` would return
my $target = "BillGates";
print "user : $User\n";print "target : $target\n";print "num(user) : ", $User + 0, "\n";print "num(target): ", $target + 0, "\n";printf "flawed \$User == \$target -> %s\n", ($User == $target) ? "TRUE" : "FALSE";printf "fixed \$User eq \$target -> %s\n", ($User eq $target) ? "TRUE" : "FALSE";$ perl -w perl_demo.plArgument "some_user" isn't numeric in addition (+) at perl_demo.pl line 13.Argument "BillGates" isn't numeric in addition (+) at perl_demo.pl line 14.user : some_usertarget : BillGatesnum(user) : 0num(target): 0flawed $User == $target -> TRUEfixed $User eq $target -> FALSEPerl 把非数字开头的字符串转成数字时取前导数字部分,没有前导数字就是 0(同时抛 isn't numeric 警告)。whoami 返回的是用户名,BillGates 也是裸字符串,两者的数值转换结果都是 0。
授权条件退化成 0 == 0,恒为真。任何用户名(root、nobody、普通用户都一样)都会走进 if 分支,打印记录再 die("Closing...")。真正的字符串判定应该用 eq:'some_user' eq 'BillGates' 为假,只有用户名恰好是 BillGates 时才通过。
if ($User eq ‘BillGates’)