写点什么

ShellShock 来袭——Bug 背后的故事

  • 2014-09-30
  • 本文字数:3281 字

    阅读完需:约 11 分钟

Bash 软件中声名狼藉的 bug,CVE-ID 为 CVE-2014-6271 (译者注:CVE 即 Common Vulnerabilities and Exposures,这个系统为公开的信息安全漏洞提供参考信息),现在有了新的名字“ShellShock”(译者注:在英语中 ShellShock 是指弹震症,一种精神疾病,参考这里)。精心伪造的数据通过网络传到一台服务器上,直接或间接触发一个bash 脚本,就可以远程执行恶意代码。最初的bug 已经修复了,但引发了人们对Bash 的解析程序可能产生0day 漏洞的关切,随后又挖掘出了第二个漏洞 CVE-2014-7169 ,这个漏洞也在前天得到了修复。但这种漏洞的根源到底是什么?同一类型的漏洞已经全部被消灭了吗?FreeBSD 和 NetBSD 已经默认关闭了自动导入函数的功能,以应对未来可能出现的漏洞。

这个问题的发生是因为 Bash 的一个功能(不是bug 吗?),它允许在Bash 的shell 中使用环境变量来定义函数。函数的作用是把经常调用的代码封装起来,然后在其他地方复用,所有的shell 脚本语言都有这个功能。Bash 中函数的定义是这样的(大多数其他shell 也是):

复制代码
function hello {
echo "Hello"
}
hello # 调用这个函数

但是,Bash 还有一种使用环境变量来定义函数的方法,这是它独有的。如果环境变量的值以字符“(){”开头,这个变量就会被当作是一个导入函数的定义,这种定义只有在 shell 启动的时候才生效。

复制代码
$ export HELLO="() { echo 'Hello'; }"
$ HELLO
-bash: HELLO: command not found
$ bash
$ HELLO
Hello

因为它只会在 shell 启动的时候生效,所以大多数用来演示这个漏洞的示例代码都只有一行:

env HELLO="() { echo 'Hello'; }" bash -c HELLO这行代码的作用跟上面的例子是一样的。(env 命令代表“先设置下面的环境变量,再运行下面的程序”,并且执行完成后当前的环境变量不受影响。实际上,直接写成 HELLO="() { echo ‘Hello’; }" bash -c HELLO 也可以。)这一行 bash 命令指定了 -c 选项是为了启动 bash 时就执行 HELLO 函数,这里必须新起一个 bash,因为只有 bash 启动的时候才会去解析函数的定义。

解析代码中最早发现的缺陷发生在 bash 解析完函数定义,执行函数的时候,所以:

env CVE_2014_6271="() { echo 'Hello';}; echo 'Goodbye'" bash -c CVE_2014_6271在修复后的系统中,上面命令的结果应该只打印“Hello”,而有漏洞的系统还会把“Goodbye”打出来。问题出在自动导入函数的解析器越过了函数定义的结尾,接着执行后面的代码——并且由于每一个新的 bash 启动时都会触发这个漏洞,相当于任意代码都能被执行了。

(译者注:读者需要明白,执行 CVE_2014_6271 这个函数并不会导致打印 Goodbye,导入 CVE_2014_6271 这个函数才会导致打印 Goodbye。把两者放在一起有一定的误导性。)

这个问题因为两个原因被放大了:首先,Bash 是一个被广泛集成的软件,所有的系统都在运行,从 Rapsberry Pis 到手机,再到数据中心的服务器以及大型机。由于自动导入函数的功能至少从 Bash 3.0 开始就存在了,所以这个 bug 有可能在大多数系统中存在近 20 年了。其次,当我们在 Apache 服务器中使用 mod_cgi(不包括 mod_php 或 mod_python)运行脚本的时候,数据是通过环境变量来传递的,这可以算是互联网领域最古老的一些技术了。其他一些客户端也会受到影响——比如 Linux 的 DHCP 客户端——它大量运用 Bash 脚本来使修改生效,这也使黑客能通过在 DHCP 数据包中加入恶意数据来达到攻击的目的。

鉴于 Bash 是大多数 Linux 系统(以及 OSX)上默认的 shell,这个漏洞就意味着,把有害数据编入环境变量,传到服务器端,触发服务器运行脚本,就完成了攻击。举个例子,HTTP 协议的头 User-Agent 通常是通过环境变量 HTTP_USER_AGENT 来传递的,这意味使用以下命令就可以利用这个漏洞了:

curl -A "() {:;}; echo 'Game Over'}" http://example.com/some-cgi/script.cgi(译者注:这条命令的意思是以"() {:;}; echo ‘Game Over’}"为 user agent 去下载那个脚本。)

对于不传递 user agent 的服务器来说,常常还有其他受攻击的可能——比如 Cookie,或者请求本身。

注意,这个 bug 不仅仅影响 CGI 脚本和 Apache——如果其他程序也收到并传递了有害的环境变量(比如 ssh 服务会接收 TERM 或 DISPLAY 环境变量),然后这些进程再运行一个 Bash 脚本(或通过 system() 调用来执行),同样的漏洞也会被利用。和 HTTP 不一样,ssh 一般不允许匿名请求——触发这个漏洞之前必须要登录——但是代码托管服务商们却允许匿名登录(哪怕只登录到一个权限受限的 shell),所以为了防止入侵, GitHub 更新了他们的企业级产品,Bitbucket 也更新了他们的服务器

CVE-2014-6271 中的 bug 修复后,问题马上就解决了,大多数厂商都及时提供了修复后的 Bash 版本。面向互联网的服务器没有理由不马上修复它,因为这个漏洞会使主机完全落入别人的控制(以 Apache 所使用的用户身份)中。

但是,大家的目光已经聚焦在这个领域,新的 bug 被发现了。同时使用 Bash 的 shell 重定向功能和函数自动导入功能, CVE-2014-7169 出现了。这回导致的结果是可以随意读写远程机器上的文件,使用的手段和上次一样,只不过这次是利用了 shell 的重定向符号 < 或 >。

env CVE_2014_7169='() { (a)=>\' bash -c "echo date"; cat echo这次解析器先停在 = 号上(由于 (a)= 不是一个有效的 Bash 表达式),但至关重要的是把 < 号留在了解析管道中。接下来的转义符\会使解析器在重定向命令之间插入一些空格(但无关紧要),最终导致了后面的命令变成了一条重定向命令:

复制代码
>echo data

这是一条有效的 Bash 命令,语义上它等价于下面这种更常见的形式:

复制代码
date >echo

注意,另外一个重定向符号 < 在这里也是有效的,它可以把输入重定向到文件。

所以这个 bug 也被修复了。有人担心,修复 Bash 的自动导入函数功能中的边界情况所引起的 bug,会演变成一场打地鼠游戏:一个bug 刚刚被消灭,另外一个马上又会冒出来。甚至在这些bug 被发现之前,就有人担心使用Bash 的自动导入函数功能会导致系统中那些不需要使用绝对路径来访问的标准程序被覆盖:

复制代码
$ env ls="() { echo 'Game over'; }" bash -c ls
Game over
$ env ls="() { echo 'Game over'; }" bash -c /bin/ls
Applications Desktop Documents Downloads ...

(在最近几个 patch 发布之前,我们可以通过 env /bin/ls="() { echo ‘Game over’; }" bash -c /bin/ls 来覆盖绝对路径,但在最新的集成所有补丁的版本中,这个问题已经被修复了。)

但是很多可执行程序在运行外部程序的时候并没有指定它的路径,这意味着精心设计好一个函数变量,就可以让程序做它不能做的事情:

复制代码
$ touch /tmp/a /tmp/b
$ env test='() { echo vulnerable >&2; }' /usr/bin/bzdiff /tmp/a /tmp/b
vulnerable
bzip2: Can't open input file a.bz2: No such file or directory.

(译者注:上面的例子的意思是,bzdiff 命令里面会调用 test 命令,但又没有通过绝对路径来调用它,所以 test 命令被我们自己伪造的 test 函数覆盖了。)

当然,有能力设置任何环境变量,可以使攻击者控制一切东西——修改 IFS 环境变量(过去被利用过的一个漏洞),甚至修改PATH 环境变量,会影响新启动的shell 脚本的行为,无论如何这些手段都会导致问题。但至少前面提到的SSH 和CGI 攻击中,涉及的环境变量要么是有限几个(TERM、DISPLAY 等),要么是以某个前缀(HTTP_USER_AGENT、HTTP_REFERRER)开头的。所以除了前缀名所代表的程序外,其他的程序受影响有限。

有些人预计Bash 自动导入函数的功能还存在安全漏洞,担心未来还会有bug 曝出。NetBSD 在Bash 中默认关闭了自动导入函数的功能 FreeBSD 也这么做了,转而以新增选项( --import-functions)的方式提供这个功能。虽然这种做法破坏了后向兼容,但这个时候小心为上,而且可能过不了多久,这个选项就会出现在上游代码(upstream)中了。OSX 的用户也有对应的补丁可以下载。

InfoQ 会关注事态发展,报道事态变化。

9 月 29 日更新:上面提到的缺陷已经在最新一组补丁中得到修复。除了苹果以外,所有厂商都提供了修复后的版本供下载。

查看英文原文: ShellShocked - Behind the Bug

2014-09-30 02:424377
用户头像

发布了 77 篇内容, 共 36.7 次阅读, 收获喜欢 26 次。

关注

评论

发布
暂无评论
发现更多内容

融云发布语聊房SDK 1.0 & Demo 满足开发者开箱即用需求

融云 RongCloud

利用 iOS 14 Vision 的手势估测功能 实作无接触即可滑动的 Tinder App

iOSer

ios ios开发 iOS 14 Vision Tinder App

零售的私域「留量」时代,SaaS的「服务」未来

ToB行业头条

Cilium 首次集成国内云服务,阿里云 ENI 被纳入新版本特性

阿里巴巴云原生

容器 运维 云原生

2021春招面试经历,阿里3轮技术面+交叉3面(已成功拿到offer)

Java 程序员 架构 面试

从字节跳动到火山引擎(二):私有云 PaaS 场景下的 Kubernetes 集群部署实践

字节跳动 云原生 #Kubernetes# 火山引擎

[译] R8 优化: 字符串操作

Antway

6月日更

英特尔谢晓清:开源是软件发展趋势

E科讯

联邦学习这件小事(二)

趣链科技

区块链 隐私保护 加密技术 联邦计算

Redis套路,一网打尽

Coder的技术之路

redis 缓存 面试

融云CTO任杰:强互动,RTC下一个“爆点”场景

融云 RongCloud

细节爆炸!阿里企业级Spring Security机密文档

Java 程序员 架构 面试 微服务

索信达控股:解析索信达模型管理利器

索信达控股

大数据 模型 风险管理 智能 数据管理平台

Mysql是如何选择主键的

架构精进之路

MySQL 6月日更 主键

年份白酒推荐 商务聚会我选唐庄五星酒

Geek_50a546

美联储最新货币政策,将如何影响比特币市场?

CECBC

四川比特币矿机或全线关机,矿工跟矿机说:Bye,See you

CECBC

华为实习结束后,鹅厂和字节跳动递来的offer让我手足无措

Java 程序员 架构 面试

曝光一个网站,我周末就耗在上面了。

why技术

Java Arthas

ZGC 新特性

meacial

Java ZGC JVM 软件开发

数字人民币对地铁App的影响分析

CECBC

并发王者课-铂金3:一劳永逸-如何理解锁的多次可重入问题

MetaThoughts

Java 多线程 并发

1.5w字 + 24张图肝翻 TCP

苹果看辽宁体育

TCP 大前端 后端 计算机网络

BZZ云算力挖矿系统开发案例

我试了试用 SQL查 Linux日志,好用到飞起

程序员小富

Java Linux 日志

唐庄酒业的酒好喝吗?纯粮酿造好味道

Geek_50a546

从字节跳动到火山引擎(三):替换 Spring Cloud,使用基于 Cloud Native 的服务治理

字节跳动 微服务 云原生 Spring Cloud 火山引擎

并发王者课-铂金4:令行禁止-为何说信号量是线程间的同步利器

MetaThoughts

Java 多线程 并发

酱香型白酒怎么选?唐庄酒告诉你答案

Geek_50a546

蚂蚁金服内部的Spring Cloud Alibaba手册,面面俱到,太全了

Java 程序员 架构 面试 微服务

案例 | 低代码助力生产制造业,扫平数字化升级“死角”!

优秀

低代码 生产管理系统

ShellShock来袭——Bug背后的故事_安全_Alex Blewitt_InfoQ精选文章