写点什么

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

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

关注

评论

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

区块链大趋势

CECBC

数字经济

K线成交量管理系统开发、成交量管理系统开发

W13902449729

K线成交量管理系统开发 成交量管理系统开发

厉害了!来看看这份超全面的《Android面试题及解析》,一线互联网公司面经总结

欢喜学安卓

android 程序员 面试 移动开发

Hadoop的MapReduce到底有什么问题?

hanke

大数据 hadoop spark mapreduce 开源

从一场营地教育直播,看懂众盟“私域流量营销”的底层逻辑

脑极体

为什么建议没事不要随便用工厂模式创建对象?

李尚智

Java 学习 设计模式

nodejs事件和事件循环详解

程序那些事

nodejs 异步编程 程序那些事 事件和事件循环 nodejs event

AES/CBC/PKCS5Padding到底是什么

kof11321

加密解密

TCP波场拼系统开发|TCP波场拼软件APP开发

系统开发

Java 程序经验小结:类层次优于标签类

后台技术汇

28天写作

并发阻塞队列(BlockingQueue)— 生产者消费者模式核心部件

李尚智

Java 架构 jdk 设计模式

DeFi流动性挖矿管理系统开发|去中心化金融借贷系统开发

W13902449729

去中心化金融借贷系统开发 DeFi流动性管理系统开发

龙归科技 |软件的成本下降

龙归科技

身份认证 企业信息化 SSO

工作11年,从阿里P8出来,头发也没了,人也虚了,就剩下这份笔记了!

Java架构之路

Java 程序员 架构 面试 编程语言

区块链发展应以密码应用创新为根基

CECBC

区块链 密码学

2021年编排将成为DevSecOps关键推动者

啸天

DevSecOps 应用安全 开发安全

超强Android进阶路线知识图谱:Kotlin可能带来的一个深坑,持续更新中

欢喜学安卓

android 程序员 面试 移动开发

关于事务、redolog 写入的两个问题分析

程序员架构进阶

MySQL innodb 事务 28天写作

中美上市软件公司对比中的投资启示

ToB行业头条

五分钟快速掌握Maven的核心概念

Java架构师迁哥

“区块链+数字身份”,道路坎坷前途光明

CECBC

数字技术

现货合约量化交易系统开发搭建

薇電13242772558

数字货币 策略模式

阿里2021年首次公开五份Java并发编程全彩小册:模型+原理+应用+模式+面试题五管齐下

Java架构追梦

Java 学习 架构 面试 并发编程

阿里面试官纯手打:金九银十跳槽必会Java核心知识点笔记整理

Java架构之路

Java 程序员 架构 面试 编程语言

持续集成对IT团队和企业分别有哪些好处?

禅道项目管理

DevOps 运维 开发 CI/CD

字节内部MySQL宝典意外流出!极致经典,堪称数据库的天花板

比伯

Java 编程 架构 面试 程序人生

盘点2020|征文大赛获奖名单公布

InfoQ写作社区官方

盘点2020 热门活动

音乐混音怎么做?教你完美制作野狼disco与周杰伦双节棍合唱!

懒得勤快

音频技术 音频制作 混音 音乐混音

细节!3部分讲明白HotSpot:运行时+编译器+垃圾回收器

996小迁

Java 架构 虚拟机 hotspot

案例研究之聊聊 QLExpress 源码 (六)

小诚信驿站

28天写作 QLExpress源码 聊聊源码

企业如何预防短信验证码被别人盗用

香芋味的猫丶

短信防刷 短信轰炸机 短信验证码 短信防轰炸 短信防火墙

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