Shellshock 和 Perl

最近,科技媒体对名为Shellshock的严重Bash 漏洞大肆炒作。媒体炒作机器全速运转,充斥着每次发现重大安全漏洞时都会出现的荒谬末日般的预测(还记得“终极网络噩梦”吗?)。虽然忽视炒作是明智的,但不要忽视问题;Shellshock是一个严重的风险,允许通过Bash环境变量进行远程代码注入和执行。这对Perl也很重要,因为Perl与系统shell有多个接触点,从内置的exec和system函数到全局变量%ENV
。
系统“x”受影响吗?
如果平台是基于Unix的操作系统,并且Bash是默认的终端,它可能存在风险。Redhat Linux、CentOS和Fedora、openSUSE、arch Linux以及Mac OSX默认情况下都存在漏洞。许多平台并不存在这种情况;freeBSD使用tsch,而Debian和Ubuntu的现代版本默认使用dash。
从Bash 4.3版本开始,每个版本都存在Shellshock漏洞。要找出您的Bash版本,请在终端中输入以下命令以打印版本
$ echo $BASH_VERSION
4.2.47(1)-release
鉴于我的Bash版本低于4.3,我的系统可能存在Shellshock漏洞。
Shellshock是如何工作的?
Shellshock利用了Bash解析环境变量的漏洞;Bash允许将函数存储在环境变量中,但问题是Bash会在环境变量值中函数之后执行任何代码。让我们来举一个例子
$ export SHELLSHOCK="() { ignore; };echo danger"
此代码创建了一个名为SHELLSHOCK
的新环境变量(环境变量名称通常使用大写字母)。新变量的值是一个匿名函数,它什么也不做:() { ignore; };
然后是:echo danger
,而这段代码的后半部分才是风险。每次Bash处理其环境变量时,都会执行这段代码。例如,如果我运行这个语句,然后输入
$ bash -c "echo Hello, World"
danger
Hello, World
可以看到打印了单词danger,表明我的代码已经通过Bash自动执行。在这种情况下,echo danger
是无害的,但攻击者可以创建恶意有效载荷,造成不可修复的损害,如身份盗窃、数据破坏或硬件损坏。
为了使Shellshock攻击生效,攻击者需要实现两个目标。首先将包含恶意代码的环境变量传送到目标主机。其次,使目标主机启动一个新的Bash进程。这种明显的目标候选人是托管CGI脚本的Web服务器。CGI通过将请求参数作为环境变量(如用户代理名称)传递来工作,如果目标CGI脚本启动一个新的Bash进程,攻击将成功。你可能想知道为什么脚本会启动一个新的Bash进程,这让我回到了这一切最初与Perl相关的原因。
Perl冲击
首先,要说明的是Perl与Shellshock无关,但Perl可能在多个地方调用系统shell,我们需要对这些情况保持警惕。在基于Unix的系统上,Perl使用位于/bin/sh
的shell二进制文件,这通常是一个指向默认shell二进制文件(如Bash)的符号链接。这意味着如果Bash是您的系统上的默认shell,当Perl调用/bin/sh
时,将启动一个新的Bash进程,并将处理环境变量,因此Perl可能成为引发Shellshock攻击的触发器。
Perl内置函数exec
和system
在使用时会调用新的shell进程。您还可以使用反引号来调用系统命令。其他Perl函数可能会调用shell,例如open
可以用来运行系统命令。
让我们来看一个Perl通过调用shell来触发Shellshock的例子。
$ perl -e 'system "echo test"'
test
咦,这里发生了什么?命令运行正常,但“危险”没有打印出来 - Shellshock失败了。实际上,Perl并不总是使用/bin/sh -c
来调用shell。为了更有效率,Perl通常会调用execvp。根据perldoc,只有当系统命令包含元字符时,Perl才会直接调用shell。让我们来测试一下。
$ perl -e 'system "echo test >> test.log"'
danger
哈,这成功了!我们使用了元字符>>
将echo
的输出重定向到一个日志文件中,Perl直接调用了shell。
最好的防御是进攻
与其担心系统调用是否包含元字符,我们可以在执行任何系统命令之前删除SHELLSHOCK
环境变量。Perl将环境变量存储在%ENV
中,所以我将从那里删除这个变量。
$ perl -e 'delete $ENV{SHELLSHOCK};system "echo test >> shellshock.log"'
在这行代码中,我提前使用delete
来删除SHELLSHOCK
环境变量,以规避风险性的system
命令。我可以看到这阻止了Shellshock,因为“危险”没有被打印出来。当然,在这个测试环境中,我知道危险环境变量的名称,但通常情况下我不会知道,所以为了找到它,你需要遍历%ENV
哈希表并删除(或替换)任何可疑变量。这行代码通过使用正则表达式来识别任何在函数声明之后包含代码的环境变量来打印出风险环境变量。
$ perl -E 'for (keys %ENV) { say if $ENV{$_} =~ /};.+/ }'
SHELLSHOCK
如你所见,它正确地识别了SHELLSHOCK
环境变量,并将其打印到命令行。从这里开始,删除变量而不是打印它只是一个简单的步骤。
$ perl -e 'for (keys %ENV) { delete $ENV{$_} if $ENV{$_} =~ /};./ }'
这只是一个概念验证,可能无法处理所有恶意构建的Shell环境变量,但通过更多研究,可以部署一个强大的正则表达式,完全消除Shellshock。
结论
总结一下,一个成功的Shellshock攻击需要将包含恶意代码的环境变量传递给在易受攻击的系统上运行的Web服务器(如Apache)上的CGI脚本,并且CGI脚本必须调用Shell。对于Perl CGI脚本,系统调用需要包含元字符。这似乎是一个相当复杂的任务,还没有被所有人理解;就像一个误将cPanel CGI脚本标记为易受攻击的安全博客作者。尽管CGI曾经很流行,但所有现代Perl Web框架都使用FastCGI并且对Shellshock免疫。现代Web服务器默认不启用CGI,一些如nginx甚至不提供CGI功能。
在易受攻击的系统上处理Shellshock的最佳方法是修补Bash到最新版本。尽管我已经展示了使用Perl可以阻止攻击,但仍可能有其他未预见的攻击向量仍然开放。
更正: 删除了关于 $SHELL 的错误描述,因为它是目前用户的默认登录 shell,而不是默认 shell。删除了对 .bashrc 的引用,因为 Bash 只会在交互式 shell 启动时处理 .bashrc。2014-09-27
本文最初发布在 PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?请在 GitHub 上打开一个 issue 或 pull request 来帮助我们。