QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

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:424510
用户头像

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

关注

评论

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

服务器运维是什么意思?日常工作包含哪些?

行云管家

运维 服务器 IT运维 服务器运维

一周信创舆情观察(8.23~8.29)

统小信uos

如何使用 Redis 实现后台房间的数据管理?

ZEGO即构

redis 架构 音视频

高可用 | Xenon 实现 MySQL 高可用架构 常用操作篇

RadonDB

MySQL 数据库 RadonDB

第一波场DAPP系统搭建,DAPP介绍

合肥艾数199四②43⑧797

拥抱开源,云智慧发布AIOps社区

BeeWorks

阅读

敏捷团队的最佳测试实践:自动化金字塔

禅道项目管理

测试 自动化测试

国资云横空出世,云上安全监管再加码

行云管家

云计算 数据安全 企业上云 国资云

Android ABI

Changing Lin

9月日更

Java + opencv 实现性别识别

张音乐

Java OpenCV 9月日更 性别识别

云小课|细数那些VMware虚拟机的恢复招式

华为云开发者联盟

vmware 云小课 云备份 VMware恢复 恢复数据

爱奇艺本地实时Cache方案

爱奇艺技术产品团队

分布式 高并发 cache

fil矿机组装教程是什么?fil矿机算力单位有哪些?fil矿机冗余是什么?

fil矿机组装教程是什么 fil矿机算力单位有哪些 fil矿机冗余是什么

开源应用中心|这款漂亮的国产开源论坛系统,放着不用太可惜!

开源软件

Python代码阅读(第23篇):将变量名称转换为短横线连接式命名风格

Felix

Python 编程 Code Programing 阅读代码

Dogfooding-爱奇艺移动端后台灰度环境优化实践

爱奇艺技术产品团队

测试 开发 灰度发布

Erda 系列 Meetup「成都站」携手SOFAStack 和你聊聊云原生基础设施建设那点事儿

尔达Erda

开发者 云原生 活动 技术人

filecoin今日价格行情?fil币能涨到1万一枚吗?

区块链 分布式存储 fil币价格预测? filecoin挖矿 filecoin价格行情

投资filecoin的最佳选择是?Filecoin挖矿的是如何月入上万的?

区块链 分布式存储 IPFS filecoin挖矿 投资filecoin

【得物技术】直播服务监控告警归因实践

得物技术

稳定性 服务 直播 告警 问题排查

BaikalDB在大规模数据场景的挑战和实践

百度开发者中心

最佳实践 方法论 存储系统

中移“校企行”专项行动即将开赛,你准备好了吗?

创业邦

什么是低代码?低代码开发对企业有哪些特殊作用和优势?

优秀

低代码开发

PhxSQL设计与实现

OpenIM

携手伙伴,共赴星海-百度飞桨应急行业AI私享会成功举办

百度大脑

人工智能 飞桨

再启动!零代码第四期训练营报名开放中

明道云

波场链DAPP智能合约系统搭建|波场链DAPP开发

Geek_23f0c3

DAPP智能合约交易系统开发 波场DAPP 波场链DAPP开发

值钱的数据放在云上安全吗?怎样才能保障其安全性?

行云管家

网络安全 信息安全 数据安全 企业上云

OpenSSL国密爆出8.1分高危漏洞CVE-2021-3711

腾讯安全云鼎实验室

漏洞分析 openssl

学习笔记20210903(python测试类,贝叶斯定理)

姬翔

9月日更

直播回顾 | 做一个有格局的工程师

鉴释

创业 工程师 CEO

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