写点什么

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

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

关注

评论

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

10行代码,撸一个在线个人简历页面!

老表

Python GitHub Linux web开发 跟老表学云服务器

微信小程序开发:使用字体图标的方法

三掌柜

11月日更

懒人畅听网,有声小说类目数据采集,多线程速采案例,Python爬虫120例之23例

梦想橡皮擦

11月日更

【Flutter 专题】08 图解页面小跳转 (一)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

CSS布局之display:flex

Augus

CSS 11月日更

创业自研技术团队筹建需要注意什么?

boshi

创业 团队管理

如何“拼”出一个页面-游戏中心模块化实践

vivo互联网技术

开发 组件化 产品方法论

作业三总结

Geek_1d37ea

架构训练营

TDSQL首次登上腾讯财报!金融机构核心系统落地实现规模化复制

腾讯云数据库

数据库 tdsql

敏捷开发专家一席谈:云原生技术下的华为云DevOps实践之路

华为云开发者联盟

DevOps 敏捷开发 华为云 devcloud

毫米波 5G 比公共 Wifi 快近 30 倍,但覆盖范围相似

吴脑的键客

网络

题目三、简述HDFS的读写流程

arctec

2021 年 Node.js 的发展趋势

CRMEB

技术架构+应用场景揭秘,为什么高斯Redis比开源香?

华为云开发者联盟

数据库 redis 开源 云原生 高斯Redis

DevOps为何在中国发展滞后?

飞算JavaAI开发助手

用明道云集成多平台多部门数据,发挥数据分析的力量

明道云

大数据训练营学习总结

arctec

模块三

MySQL打印死锁日志

Simon

MySQL 死锁

CodeGuide 300+文档、100+代码库,一个指导程序员写代码的,Github 仓库开源啦!

小傅哥

Java GitHub 小傅哥 开源社区 代码库

TDSQL | 多类型数据库统一管理,腾讯云数据库DBhouse工具重磅发布

腾讯云数据库

数据库 tdsql

新时代下如何构建TDSQL-C数据库产品

腾讯云数据库

数据库 tdsql

新机遇,拨开证劵企业生态转型迷雾

大咖说

云计算 阿里云 数字化转型 数字化 企业上云

用vscode创建第一个flutter项目

坚果

flutter 11月日更

openLooKeng v1.4.1 上线,OmniData Connector 来了

LooK

大数据 openLooKeng

设计消息队列存储消息数据的MySQL表格

毛先生

详细剖析Kafka架构及组件

五分钟学大数据

11月日更

如何在 JavaScript 中操作二维数组

devpoint

JavaScript array 数组操作 11月日更

体验内容更新,MindSpore轻松掌握

Geek_6cdeb6

Flink CDC 2.0 数据处理流程全面解析

大数据技术指南

11月日更

8大原则带你秒懂Happens-Before原则

华为云开发者联盟

线程 并发 Happens-Bfore Java内存

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