Bash中的Shellshock漏洞背后的行为是否logging在案或完全有意?

披露了最近的一个漏洞, CVE-2014-6271 , Bash如何解释环境variables。 该漏洞利用Bashparsing一些环境variables声明作为函数定义,但是继续执行下面定义的代码:

$ x='() { echo i do nothing; }; echo vulnerable' bash -c ':' vulnerable 

但我不明白。 在Bash手册中,我没有find关于将环境variables解释为函数的东西(除了inheritance函数 ,这是不同的)。 事实上,一个正确的命名函数定义只是被视为一个值:

 $ x='y() { :; }' bash -c 'echo $x' y() { :; } 

但是一个腐败的人什么也不打印:

 $ x='() { :; }' bash -c 'echo $x' $ # Nothing but newline 

腐败的function是未命名的,所以我不能只是调用它。 这个漏洞是一个纯粹的实现错误,还是在这里有一个预期的function,我只是看不到?

更新

Per Barmar的评论中,我假设函数的名字是参数名称:

 $ n='() { echo wat; }' bash -c 'n' wat 

我可以发誓我曾经尝试过,但我想我没有努力。 现在是可重复的。 这里有更多的testing:

 $ env n='() { echo wat; }; echo vuln' bash -c 'n' vuln wat $ env n='() { echo wat; }; echo $1' bash -c 'n 2' 3 -- 4 wat 

…显然这些参数在攻击执行的时候没有设置。

无论如何,我的问题的基本答案是,这是Bash如何实现inheritance的function

这看起来像是一个执行错误。

显然,导出函数在bash工作方式是使用特殊格式的环境variables。 如果你导出一个函数:

 f() { ... } 

它定义了一个如下的环境variables:

 f='() { ... }' 

可能发生的情况是,当新shell看到一个以()开头的环境variables时,它会预先给出variables名并执行结果string。 错误在于,这包括在函数定义之后执行任何事情。

描述的修复显然是parsing结果,看看它是否是一个有效的函数定义。 如果不是,则打印关于无效函数定义尝试的警告。

本文确认了我对错误原因的解释。 它还会详细介绍修复程序如何解决这个问题:它们不仅更仔细地parsing值,而且用于传递导出函数的variables遵循特定的命名约定。 这个命名约定与为CGI脚本创build的环境variables所使用的约定不同,所以HTTP客户端应该永远不能进入这个门。

下列:

 x='() { echo I do nothing; }; echo vulnerable' bash -c 'typeset -f' 

版画

 vulnerable x () { echo I do nothing } declare -fx x 

似乎比Bash,在分析了x=... ,发现了它作为一个函数,导出了它,看到了declare -fx x并允许在声明之后执行该命令。

echo vulnerable

 x='() { x; }; echo vulnerable' bash -c 'typeset -f' 

打印:

 vulnerable x () { echo I do nothing } 

并运行x

 x='() { x; }; echo Vulnerable' bash -c 'x' 

版画

 Vulnerable Segmentation fault: 11 

segfaults – 无限recursion调用

它不覆盖已经定义的函数

 $ x() { echo Something; } $ declare -fx x $ x='() { x; }; echo Vulnerable' bash -c 'typeset -f' 

打印:

 x () { echo Something } declare -fx x 

例如,x保留之前(正确)定义的function。

对于Bash 4.3.25(1)-release该漏洞是封闭的,所以

 x='() { echo I do nothing; }; echo Vulnerable' bash -c ':' 

版画

 bash: warning: x: ignoring function definition attempt bash: error importing function definition for `x' 

但是 – 什么是奇怪的 (至less对我来说)

 x='() { x; };' bash -c 'typeset -f' 

仍然打印

 x () { x } declare -fx x 

 x='() { x; };' bash -c 'x' 

分段错误,所以它仍然接受奇怪的function定义…

我认为值得看看Bash代码本身。 该补丁给出了一些有关该问题的见解。 尤其是,

 *** ../bash-4.3-patched/variables.c 2014-05-15 08:26:50.000000000 -0400 --- variables.c 2014-09-14 14:23:35.000000000 -0400 *************** *** 359,369 **** strcpy (temp_string + char_index + 1, string); ! if (posixly_correct == 0 || legal_identifier (name)) ! 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)) --- 364,372 ---- strcpy (temp_string + char_index + 1, string); ! /* Don't import function names that are invalid identifiers from the ! environment, though we still allow them to be defined as shell ! variables. */ ! if (legal_identifier (name)) ! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD); if (temp_var = find_function (name)) 

当Bash导出一个函数时,它显示为一个环境variables,例如:

 $ foo() { echo 'hello world'; } $ export -f foo $ cat /proc/self/environ | tr '\0' '\n' | grep -A1 foo foo=() { echo 'hello world' } 

当一个新的Bash进程发现一个在其环境中以这种方式定义的函数时,它使用parse_and_execute()parse_and_execute()variables中的代码。 对于普通的非恶意代码,执行它只是在Bash中定义函数并继续。 然而,因为它被传递给一个通用的执行函数,所以Bash将在函数定义之后正确parsing并执行在该variables中定义的其他代码

您可以看到,在新代码中,添加了一个名为SEVAL_ONECMD的标志,它告诉Bash仅评估第一个命令(即函数定义)和SEVAL_FUNCDEF以仅允许函数定义。

关于你关于文档的问题,请在env命令的命令行文档中注意,对语法的研究表明env按照文档工作。

  • 有4种可能的select
  • 一个可选的连字符作为-i的同义词(为了向后兼容性,我假设)
  • 零个或多个NAME = VALUE个对。 这些是可能包含函数定义的variables赋值。
  • 请注意,在分配之间或之后不需要分号(;)。
  • 最后一个参数可以是一个单一的命令,然后是它的参数。 它将以授予正在使用的login名的权限运行。 安全性是通过限制login用户的权限和对用户可访问的可执行文件设置权限来控制的,这样除可执行文件的所有者以外的用户只能读取和执行该程序,而不能对其进行修改。
 [ spot@LX03:~ ] env --help Usage: env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...] Set each NAME to VALUE in the environment and run COMMAND. -i, --ignore-environment start with an empty environment -u, --unset=NAME remove variable from the environment --help display this help and exit --version output version information and exit A mere - implies -i. If no COMMAND, print the resulting environment. Report env bugs to bug-coreutils@gnu.org GNU coreutils home page: <http://www.gnu.org/software/coreutils/> General help using GNU software: <http://www.gnu.org/gethelp/> Report env translation bugs to <http://translationproject.org/team/>