2014年10月9日星期四

bash代码注入的安全漏洞

很多人或许对上半年发生的安全问题“心脏流血”(Heartbleed Bug)事件记忆颇深,这两天,又出现了另外一个“毁灭级”的漏洞——Bash软件安全漏洞。这个漏洞由法国GNU/Linux爱好者Stéphane Chazelas所发现。随后,美国电脑紧急应变中心(US-CERT)、红帽以及多家从事安全的公司于周三(北京时间9月24日)发出警告。 关于这个安全漏洞的细节可参看美国政府计算安全的这两个漏洞披露:CVE-2014-6271 和 CVE-2014-7169
这个漏洞其实是非常经典的“注入式攻击”,也就是可以向 bash注入一段命令,从bash1.14 到4.3都存在这样的漏洞。我们先来看一下这个安全问题的症状。

Shellshock (CVE-2014-6271)

下面是一个简单的测试:
1
env VAR='() { :;}; echo Bash is vulnerable!' bash -c "echo Bash Test"
如果你发现上面这个命令在你的bash下有这样的输出,那你就说明你的bash是有漏洞的:
1
2
Bash is vulnerable!
Bash Test
简单地看一下,其实就是向环境变量中注入了一段代码 echo Bash is vulnerable。关于其中的原理我会在后面给出。
很快,CVE-2014-6271的官方补丁出来的了——Bash-4.3 Official Patch 25

AfterShock – CVE-2014-7169 (又叫Incomplete fix to Shellshock)

但随后,马上有人在Twitter上发贴——说这是一个不完整的fix,并给出了相关的攻击方法。
也就是下面这段测试代码(注意,其中的sh在linux下等价于bash):
1
env X='() { (a)=>\' sh -c "echo date"; cat echo
上面这段代码运行起来会报错,但是它要的就是报错,报错后会在你在当前目录下生成一个echo的文件,这个文件的内容是一个时间文本。下面是上面 这段命令执行出来的样子。
1
2
3
4
5
$ env X='() { (a)=>\' sh -c "echo date"; cat echo
sh: X: line 1: syntax error near unexpected token `='
sh: X: line 1: `'
sh: error importing function definition for `X'
Sat Sep 27 22:06:29 CST 2014
这段测试脚本代码相当的诡异,就像“天书”一样,我会在后面详细说明这段代码的原理。

原理和技术细节

要说清楚这个原理和细节,我们需要从 bash的环境变量开始说起。
bash的环境变量
环境变量大家知道吧,这个不用我普及了吧。环境变量是操作系统运行shell中的变量,很多程序会通过环境变量改变自己的执行行为。在bash中要定义一个环境变量的语法很简单(注:=号的前后不能有空格):
1
$ var="hello world"
然后你就可以使用这个变量了,比如:echo $var什么的。但是,我们要知道,这个变量只是一个当前shell的“局部变量”,只在当前的shell进程中可以访问,这个shell进程fork出来的进程是访问不到的。
你可以做这样的测试:
1
2
3
4
5
$ var="hello coolshell"
$ echo $var
hello coolshell
$ bash
$ echo $var
上面的测试中,第三个命令执行了一个bash,也就是开了一个bash的子进程,你就会发现var不能访问了。
为了要让shell的子进程可以访问,我们需要export一下:
1
$ export var="hello coolshell"
这样,这个环境变量就会在其子进程中可见了。
如果你要查看一下有哪些环境变量可以在子进程中可见(也就是是否被export了),你可使用env命令。不过,env命令也可以用来定义export的环境变量。如下所示:
1
$ env var="hello haoel"
有了这些基础知识还不够,我们还要知道一个基础知识——shell的函数。
bash的函数
在bash下定义一个函数很简单,如下所示:
1
2
3
$ foo(){ echo "hello coolshell"; }
$ foo
hello coolshell
有了上面的环境变量的基础知识后,你一定会想试试这个函数是否可以在子进程中调用,答案当然是不行的。
1
2
3
4
5
6
$ foo(){ echo "hello coolshell"; }
$ foo
hello coolshell
$ bash
$ foo
bash: foo: command not found
你看,和环境变量是一样的,如果要在子进程中可以访问的话,那么,还是一样的,需要export,export有个参数 -f,意思是export一个函数。如:
1
2
3
4
5
6
7
$ foo(){ echo "hello coolshell"; }
$ foo
hello coolshell
$ export -f foo
$ bash
$ foo
hello coolshell
好了,我讲了这么半天的基础知识,别烦,懂了这些,你才会很容易地理解这两个漏洞是怎么回事。
好,现在要进入正题。
bash的bug
从上面我们可以看到,bash的变量和函数用了一模一样的机制,如果你用env命令看一下export出来的东西,你会看到上面我们定义的变量和函数都在,如下所示(我省略了其它的环境变量):
1
2
3
4
$ env
var=hello coolshell
foo=() { echo "hello coolshell"
}
原来,都用同样的方式啊——无论是函数还是变量都是变量啊。于是,看都不用看bash的源代码,聪明的黑客就能猜得到——bash判断一个环境变量是不是一个函数,就看它的值是否以”()”开始。于是,一股邪念涌上心头。
黑客定义了这样的环境变量(注:() 和 { 间的空格不能少):
1
$ export X='() { echo "inside X"; }; echo "outside X";'
env一下,你会看到X已经在了:
1
2
$ env
X=(){ echo "inside X"; }; echo "outside X";
然后,当我们在当前的bash shell进程下产生一个bash的子进程时,新的子进程会读取父进程的所有export的环境变量,并复制到自己的进程空间中,很明显,上面的X变量的函数的后面还注入了一条命令:echo “outside X”,这会在父进程向子进程复制的过程中被执行吗?(关于fork相关的东西你可以看一下我以前写的《fork的一个面试题》)
答案是肯定的。
1
2
3
$ export X='() { echo "inside X"; }; echo "outside X";'
$ bash
outside X
你看,一个代码注入就这样完成了。这就是bash的bug—— 函数体外面的代码被默认地执行了
我们并不一定非要像上面那样创建另一个bash的子进程,我们可以使用bash -c的参数来执行一个bash子进程命令。就像这个安全漏洞的测试脚本一样:
1
env VAR='() { :;}; echo Bash is vulnerable!' bash -c "echo Bash Test"
其中,() { :;} 中的冒号就相当于/bin/true,返回true并退出。而bash -c其实就是在spawn一个bash的echo的子进程,用于触发函数体外的echo命令。所以,更为友好一点的测试脚本应该是:
1
env VAR='() { :;}; echo Bash is vulnerable!' bash -c "echo 如果你看到了vulnerable字样说明你的bash有安全问题"
OK,你应该明白这个漏洞是怎么一回事了吧。

bash漏洞的影响有多大

在网上看到好多人说这个漏洞不大,还说这个事只有那些陈旧的执行CGI脚本的网站才会有,现在已经没有网站用CGI了。我靠,这真是无知者无畏啊。
我举个例子,如果你的网站中有调用操作系统的shell命令,比如你用PHP执行个exec之类的东西。这样的需求是有的,特别是对于一些需要和操作系统交互的重要的后台用于系统管理的程序。于是就会开一个bash的进程来执行。
我们还知道,现在的HTTP服务器基本上都是以子进程式的,所以,其中必然会存在export 一些环境变量的事,而有的环境变量的值是从用户端来的,比如:HTTP_USER_AGENT这样的环境变量,只由浏览器发出的。其实这个变量你想写成什么就写成什么。
于是,我可以把这个HTTP_USER_AGENT的环境变量设置成上述的测试脚本,只不过,我会把echo Bash is vulnerable!这个东西换成别的更为凶残的命令。呵呵。
关于这个漏洞会影响哪些已有的系统,你可以自己Google,几乎所有的报告这个漏洞的文章都说了(比如:这篇这篇),我这里就不复述了。
注:如果你要看看你的网站有没有这样的问题,你可以用这个在线工具测试一下:‘ShellShock’ Bash Vulnerability CVE-2014-6271 Test Tool
现在,你知道这事可能会很大了吧。还不赶快去打补丁。(注,yum update bash 把bash版本升级到 4.1.2-15.el6_5.2 , )

关于 AfterShock – CVE-2014-7169 测试脚本的解释

很多同学没有看懂下面这个测试脚本是什么意思,我这里解释一下。
1
env X='() { (a)=>\' sh -c "echo date"; cat echo
  • X='() { (a)=>\’ 这个不用说了,定义一个X的环境变量。但是,这个函数不完整啊,是的,这是故意的。另外你一定要注意,\’不是为了单引号的转义,X这个变量的值就是 () { (a)=>\
  • 其中的 (a)=这个东西目的就是为了让bash的解释器出错(语法错误)。
  • 语法出错后,在缓冲区中就会只剩下了 “>\”这两个字符。
  • 于是,这个神奇的bash会把后面的命令echo date换个行放到这个缓冲区中,然后执行。
相当于在shell 下执行了下面这个命令:
1
2
$ >\
echo date
如果你了解bash,你会知道 \ 是用于命令行上换行的,于是相当于执行了:
1
$ >echo date
这不就是一个重定向么?上述的命令相当于:
1
$ date > echo
于是,你的当前目录下会出现一个echo的文件,这个文件的内容就是date命令的输出。
能发现这个种玩法的人真是个变态,完全是为bash的源代码量身定制的一个攻击
(全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn ,请勿用于任何商业用途)

每日英语

Learn from yesterday, live for today, look to tomorrow.
学习昨天,活在今天,展望明天。

2014年10月8日星期三

Traffic Manager:Azure中国版 正式发布

我们很高兴地宣布 Azure Traffic Manager 现已面向中国版 Azure正式发布。此版本现已投入生产,由企业 SLA 支持,随时可用于生产场景中。
借助 Azure Traffic Manager,您可以控制用户流量到托管在 Azure 内部或外部的应用程序的分配。您的应用程序可以在同一数据中心运行,并且可以分发到全球不同地区甚至本地托管的端点。Traffic Manager 的工作原理是,将智能路由策略引擎应用于对您的域名执行的域名服务 (DNS) 查询,并将 DNS 路由映射到相应的应用程序实例。
您可以使用 Traffic Manager 提高应用程序的可用性 - 方法是在您的某一应用程序实例出现问题时启用自动客户流量故障转移方案。您还可以使用 Traffic Manager 提高应用程序的性能 - 方法是自动将客户路由到离他们最近的应用程序实例(例如,您可以设置 Traffic Manager,以将中国北部的客户路由到应用程序的中国北部实例,将中国东部的客户路由到应用程序的中国东部实例)。此外,Traffic Manager 还可用来实现内部部署端点以及托管在其他 Azure 实例中的端点的流量负载平衡
Traffic Manager 支持云服务、Azure 网站和外部端点作为同一 Traffic Manager 配置文件中的对等点。
实现高可用性
Traffic Manager 可监控在其内部配置的每个应用程序/服务端点的运行状况,并在任何服务出现故障时自动将流量重定向到其他应用程序/服务端点。
借助 Traffic Manager,您可以配置用于监控端点运行状况的协议、端口和监控路径。您可以使用您的任何网页作为监控路径,也可以使用专用的监控页面,让您实现自己的客户运行状况检查逻辑。
提高性能
您可以在不同地理区域部署应用程序或服务的多个实例,并使用 Traffic Manager 的“性能”负载平衡策略自动将最终用户定向到最近的应用程序实例。这样可减少最终用户的网络延迟,从而提高性能。
请注意,端点监控和故障转移是所有 Traffic Manager 负载平衡策略而不仅仅是“故障转移”策略的一个特性。这意味着,如果其中一个实例出现问题并脱机,Traffic Manager 会自动将所有用户定向到运行状况良好的实例。
无缝的应用程序更新
您也可以在 Traffic Manager 中明确启用和禁用每个应用程序/服务端点。要执行此操作,只需选择端点,然后单击 Disable 命令。
这并不会停止底层应用程序,而只是告知 Traffic Manager 将流量路由到别处。这使您能够在对特定的应用程序/服务部署进行更新和测试时从其迁移出流量,然后恢复服务,所有这些操作只需单击几下即可完成。
支持使用外部端点的混合场景
Traffic Manager 通过对外部端点的支持,支持混合内部部署和跨 Azure 实例场景。利用这些场景,可以跨内部部署设备和 Azure 云实现流量负载平衡,从而实现“扩展到云”、“快速过渡到云”、“故障转移到云”或“故障转移到内部部署”场景。
此外,对外部端点的支持使应用程序能够将 Azure 实例无缝跨越到最终用户。这使得中国版 Azure 中的 Traffic Manager 能够展示跨中国版 Azure 和公共 Azure 托管的应用程序,并使公共 Azure 中的 Traffic Manager 能够跨公共 Azure 和中国版 Azure 中的应用程序实例实现负载平衡。
正式发布
由于 Traffic Manager 在支持高可用性应用程序方面起着关键作用,因此 Traffic Manager 本身具有高可用性当然也很重要。这正是我们在正式发布中宣布 Traffic Manager 的 SLA 正常运行时间将高达 99.99% 的原因所在。

朋友就要去广州了

    今天,朋友就要去广州了。
这个朋友5年多没见面了。今天趁着在等车的机会,我们一块儿坐了坐。
唯一的感觉,时间过得真快!

励志语录:马云25条经典励志语录

1、当你成功的时候,你说的所有话都是真理。

2、我永远相信只要永不放弃,我们还是有机会的。最后,我们还是坚信一点,这世界上只要有梦想,只要不断努力,只要不断学习,不管你长得如何,不管是这样,还是那样,男人的长相往往和他的的才华成反比。今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。

3、孙正义跟我有同一个观点,一个方案是一流的Idea加三流的实施;另外一个方案,一流的实施加三流的Idea,哪个好?我们俩同时选择一流的实施,三流的Idea.

4、我既要扔鞭炮,又要扔炸弹。扔鞭炮是为了吸引别人的注意,迷惑敌人;扔炸弹才是我真正的目的。不过,我可不会告诉你我什么时候扔鞭炮,什么时候扔炸弹。游戏就是要虚虚实实,这样才开心。如果你在游戏中感到很痛苦,那说明你的玩法选错了。

5、“其实,有的时候人的最大问题就在于他说的都是对的”

6、那些私下忠告我们,指出我们错误的人,才是真正的朋友。

7、我生平最高兴的,就是我答应帮助人家去做的事,自己不仅是完成了,而且比他们要求的做得更好,当完成这些信诺时,那种兴奋的感觉是难以形容的……

8、注重自己的名声,努力工作、与人为善、遵守诺言,这样对你们的事业非常有帮助。
9、商业合作必须有三大前提:一是双方必须有可以合作的利益,二是必须有可以合作的意愿,三是双方必须有共享共荣的打算。此三者缺一不可。

10、服务是全世界最贵的产品,所以最佳的服务就是不要服务,最好的服务就是不需要服务。

11、永远不要跟别人比幸运,我从来没想过我比别人幸运,我也许比他们更有毅力,在最困难的时候,他们熬不住了,我可以多熬一秒钟、两秒钟。

12、今天到北大演讲心里特别激动。我一直把北大的学子当做我的偶像,一直考却考不进,所以我想如果有一天我一定要到北大当老师。

13、看见10只兔子,你到底抓哪一只?有些人一会儿抓这个兔子,一会儿抓那个兔子,最后可能一只也抓不住。CEO的主要任务不是寻找机会而是对机会说NO.机会太多,只能抓一个。我只能抓一只兔子,抓多了,什么都会丢掉、

14、我们公司是每半年一次评估,评下来,虽然你的工作很努力,也很出色,但你就是最后一个,非常对不起,你就得离开。

15、我们与竞争对手最大的区别就是我们知道他们要做什么,而他们不知道我们想做什么。我们想做什么,没有必要让所有人知道。

16、网络上面就一句话,光脚的永远不怕穿鞋的。
17、中国电子商务的人必须要站起来走路,而不是老是手拉手,老是手拉着手要完蛋。我是说阿里巴巴发现了金矿,那我们绝对不自己去挖,我们希望别人去挖,他挖了金矿给我一块就可以了。

18、我深信不疑我们的模式会赚钱的,亚马逊是世界上最长的河,8848是世界上最高的山,阿里巴巴是世界上最富有的宝藏。一个好的企业靠输血是活不久的,关键是自己造血。

19、我为什么能活下来?第一是由于我没有钱,第二是我对INTERNET一点不懂,第三是我想得像傻瓜一样。

20、发令枪一响,你是没时间看你的对手是怎么跑的。只有明天是我们的竞争对手。

21、如果早起的那只鸟没有吃到虫子,那就会被别的鸟吃掉。

22、听说过捕龙虾富的,没听说过捕鲸富的。

23、好的东西往往都是很难描述的。

24、在我看来有三种人,生意人:创造钱;商人:有所为,有所不为。企业家:为社会承担责任。企业家应该为社会创造环境。企业家必须要有创新的精神。

25、一个公司在两种情况下最容易犯错误,第一是有太多的钱的时候,第二是面对太多的机会,一个CEO看到的不应该是机会,因为机会无处不在,一个CEO更应该看到灾难,并把灾难扼杀在摇篮里。

今天我重新排版了我的博客

    看到我的博客格式很不好,好像少了点什么!
首先,将博客归档从右转移到左,更符合我的习惯。
然后,将博客归档的格式进行了改变,改成按周归档,并且格式我月/日

每日英语

No man needs a vacation much as the man who has just had one.
没有比刚刚度过假的人更需要假期的了。

Mysql密码忘记重置

MySQL密码的恢复方法之一
1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库。 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态下,其他的用户也可以任意地登录和修改MySQL的信息。可以采用将MySQL对外的端口封闭,并且停止Apache以及所有的用户进程的方法实现服务器的准安全状态。最安全的状态是到服务器的Console上面操作,并且拔掉网线。
2.修改MySQL的登录设置: 
# vi /etc/my.cnf 
在[mysqld]的段中加上一句:skip-grant-tables 保存并且退出vi。
3.重新启动mysqld 
# /etc/init.d/mysqld restart  ( service mysqld restart )
4.登录并修改MySQL的root密码
mysql> USE mysql ; 
mysql> UPDATE user SET Password = password ( 'new-password' ) WHERE User = 'root' ; 
mysql> flush privileges ; 
mysql> quit
5.将MySQL的登录设置修改回来 
# vi /etc/my.cnf 
将刚才在[mysqld]的段中加上的skip-grant-tables删除 
保存并且退出vi。
6.重新启动mysqld 
# /etc/init.d/mysqld restart   ( service mysqld restart )
7.恢复服务器的正常工作状态
将步骤一中的操作逆向操作。恢复服务器的工作状态。

MySQL密码的恢复方法之二
如果忘记了MySQL的root密码,可以用以下方法重新设置:
1. KILL掉系统里的MySQL进程; 
killall -TERM mysqld
2. 用以下命令启动MySQL,以不检查权限的方式启动; 
safe_mysqld --skip-grant-tables &
3. 然后用空密码方式使用root用户登录 MySQL; 
mysql -u root
4. 修改root用户的密码; 
mysql> update mysql.user set password=PASSWORD('新密码') where User='root'; 
mysql> flush privileges; 
mysql> quit 
重新启动MySQL,就可以使用新密码登录了

MySQL密码的恢复方法三
有可能你的系统没有 safe_mysqld 程序(比如我现在用的 ubuntu操作系统, apt-get安装的mysql) , 下面方法可以恢复
1. 停止mysqld; 
/etc/init.d/mysql stop
(您可能有其它的方法,总之停止mysqld的运行就可以了)
2. 用以下命令启动MySQL,以不检查权限的方式启动; 
mysqld --skip-grant-tables &
3. 然后用空密码方式使用root用户登录 MySQL; 
mysql -u root
4. 修改root用户的密码; 
mysql> update mysql.user set password=PASSWORD('newpassword') where User='root'; 
mysql> flush privileges; 
mysql> quit 
重新启动MySQL
/etc/init.d/mysql restart
就可以使用新密码 newpassword 登录了。