这几天有一个关于bash的安全漏洞在网上闹得沸沸扬扬,一看真的不得 了,检查了一遍我自己的网站和服务,还好没有受到影响。网上不断有人在 吹,这个漏洞比之前的Heartbleed还要严重,那它到底是怎么回事?
用环境变量向子进程传递数据
或许各位都已经知道了,在Unix、Linux甚至是Windows下,都可以通过环境变 量向新建的进程传递数据, 而且这是很常用的做法,就像这样:
1 2 3 |
|
这里v
成为了bash子进程的环境变量,可以被bash直接引用。当然这不止局
限于父进程也是bash的情况。我们可以换成Python:
1 2 3 4 5 6 7 8 |
|
用环境变量向子进程传递代码
其实除了数据,环境变量还可以包含shell程序——好吧我也是看到Shellshock 漏洞之后才知道原来bash还有这种feature的:
1 2 3 |
|
是不是碉堡了?在子进程里直接引用环境变量的名字,就可以调用本来包含 在环境变量里的代码。相应地,这个环境变量在子进程里不再存在了:
1 |
|
也就是说bash子进程把环境变量解析成函数,然后删除掉了。
Shellshock的成因
有人发现下面这段代码能够“正常”执行,只是执行结果很诡异:
1 2 3 |
|
这里可以看到即便子进程根本没有调用v
函数,环境变量里的一部分代码
也被执行了。这是因为bash子进程在将环境变量值解析为函数的时候,将
}
之后的代码也一并执行了,而不管这些代码是不是函数定义的一部分。
这个问题在其他程序exec一个bash进程的时候也会出现:
1 2 3 4 5 6 7 8 |
|
CGI的请求处理过程
CGI曾经是生成动态网页的主流标准,随着C10K problem以及各 种异步框架(像是node.js)的出现,才渐渐淡出视野。但即使是现在也依 然有很多很多的网站依然在使用CGI技术。
有的CGI框架在处理请求时,首先会fork出一个bash进程(而不是对应语言 的解析器进程),不管页面的具体实现是Perl、Python还是别的什么东西。 然后header之类的HTTP请求参数被扔到环境变量里传递到这个bash子进程 里去,再由这个bash进程去调用具体的页面语言解析器。
Shellshock带来的问题在于,环境变量里出现的程序代码可以被立即执行, 而基本上所有的CGI框架都没有对环境变量的值做检查。所以我们可以构造 这样一个HTTP请求进行攻击:
1 2 3 |
|
这样只要CGI框架fork了一个bash进程并且把Pragma
作为环境变量传递过
去了,我们就得到一个remote shell了。
免疫的和有危险的系统
就网站来说,使用主流异步服务器/框架——像nginx、node.js——的基本上是 安全的,只要别在业务逻辑里随便fork bash进程一般就没有问题。
而使用CGI的网站就比较危险了,请检查CGI框架是不是直接调用的语言解 析器。如果中间套了一个bash进程的话,就铁定是中招了。不过到今天为 止应该大多数的发行版都已经更新了打过补丁的bash,只要'yum'或者 'apt-get'一下就够了。
除了网站服务器以外,其他利用了环境变量的程序也是有危险性的,像已 经发现的就有OpenSSH、DHCPClient以及各种shell脚本。
一个插曲
在Redhat给bash打了第一个补丁之后,有人发现这个补丁检查了函数定 义的边界,但是并没有处理函数解析过程中发生的错误,于是又有了这 么一段攻击代码:
1 |
|
这段代码很有意思,即便函数定义不完整而且会报错,date
命令
还是被执行了。Redhat随后再发了一个补丁才把这个问题也修好。
Coolshell上有一篇文章也解释了Shellshock,而且有对上面这段代 码的进一步说明。