首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Shellshock休克bug的奇怪Bash函数导出

Shellshock休克bug的奇怪Bash函数导出
EN

Stack Overflow用户
提问于 2014-09-24 19:59:38
回答 3查看 493关注 0票数 1

为什么代码

代码语言:javascript
复制
date
bash -c "date"
declare -x date='() { echo today; }' #aka export date='() { echo today; }'
date
bash -c "date"

打印

代码语言:javascript
复制
Wed Sep 24 22:01:50 CEST 2014
Wed Sep 24 22:01:50 CEST 2014
Wed Sep 24 22:01:50 CEST 2014
today

评估在哪里(以及为什么)?

代码语言:javascript
复制
 date$date

发生和得到

代码语言:javascript
复制
 date() {echo today; }

广告:@Etan Reisner

  1. 我导出了一个变量,而不是函数。Bash利用它做了一个函数。这个
代码语言:javascript
复制
export date='someting'

仍然是一个变量,而不管其内容如何。那么,为什么

代码语言:javascript
复制
export date='() { echo something; }' #Note, it is a variable, not function.

转换成一个函数?

  1. 上面提到的安全咨询讨论了在变量之后执行命令的问题,例如,
代码语言:javascript
复制
x='() { echo I do nothing; }; echo vulnerable' bash -c ':'
                              ^^^^^^^^^^^^^^^
                              This is executed - this vunerability is CLOSED in version 4.3.25(1).

env定义后的命令不会在最新的Bash中执行。

但问题仍然存在--为什么Bash将导出的变量转换为函数?

这是一个基于@chepner的答案的bug ;)完整演示:

代码语言:javascript
复制
#Define three variables
foo='() { echo variable foo; }'    # ()crafted
qux='() { echo variable qux; }'    # ()crafted
bar='variable bar'                 # Normal
export foo qux bar                 # Export

#Define the same name functions (but not qux!)
foo() { echo "function foo"; }
bar() { echo "function bar"; }
declare -fx foo bar                 #Export

#printouts
echo "current shell foo variable:=$foo="
echo "current shell foo function:=$(foo)="
echo "current shell bar variable:=$bar="
echo "current shell bar function:=$(bar)="
echo "current shell qux variable:=$qux="
echo "current shell qux function:=$(qux)="

#subshell
bash -c 'echo subshell foo variable:=$foo='
bash -c 'echo subshell foo command :=$(foo)='
bash -c 'echo subshell bar variable:=$bar='
bash -c 'echo subshell bar command :=$(bar)='
bash -c 'echo subshell qux variable:=$qux='
bash -c 'echo subshell qux command :=$(qux)='

版画

代码语言:javascript
复制
current shell foo variable:=() { echo variable foo; }=
current shell foo function:=function foo=
current shell bar variable:=variable bar=
current shell bar function:=function bar=
current shell qux variable:=() { echo variable qux; }=
tt: line 20: qux: command not found
current shell qux function:==
subshell foo variable:==                   #<-- LOST the exported foo variable
subshell foo command :=function foo=
subshell bar variable:=variable bar=
subshell bar command :=function bar=
subshell qux variable:==                   #<-- And the variable qux got converted to
subshell qux command :=variable qux=       #<-- function qux in the subshell (!!!).

避免冗长的注释,下面是来自Bash源的代码:

代码语言:javascript
复制
 if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
                                                           ^^^^^^^^ THE PROBLEM
    {
      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);

      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()=() {...} */

“古”(似乎)更好..。:)

代码语言:javascript
复制
      if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
        name[char_index - 2] = '\0';
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-09-24 20:46:02

要记住的关键是

代码语言:javascript
复制
foo='() { echo 5; }'

只使用看起来很像函数的字符串定义字符串参数。它仍然是一个常规字符串:

代码语言:javascript
复制
$ echo $foo
() { echo 5; }

而不是一种功能:

代码语言:javascript
复制
$ foo
bash: foo: command not found

一旦foo被标记为出口,

代码语言:javascript
复制
$ export foo

任何子Bash都会在其环境中看到以下字符串:

代码语言:javascript
复制
foo=() { echo 5; }

通常,这些字符串成为shell变量,使用=前面的部分作为名称和值后面的部分。但是,Bash专门通过定义函数来处理这些字符串:

代码语言:javascript
复制
$ echo $foo

$ foo
5

您可以看到,通过使用Bash以外的其他方法检查环境本身,环境本身并没有改变:

代码语言:javascript
复制
$ perl -e 'print $ENV{foo}\n"'
() { echo 5
}

(显然,父Bash在创建子环境时用换行符替换分号)。只有子Bash才会创建一个函数,而不是这样一个字符串中的shell变量。

foo既可以是一个参数,也可以是同一个shell中的一个函数;

代码语言:javascript
复制
$ foo=5
$ foo () { echo 9; }
$ echo $foo
5
$ foo
9

解释为什么需要-fexportexport foo将导致将字符串foo=5添加到子环境中;export -f foo用于添加字符串foo=() { echo 9; }

票数 4
EN

Stack Overflow用户

发布于 2014-09-24 20:18:19

实际上,您是在手动导出一个名为date的函数。(因为这是bash内部用于导出函数的格式。这是Barmar在他的回答中提出的。这个机制至少被提到了这里。)

然后,当您运行bash时,它会看到导出的函数,并在告诉它运行date时使用它。

那麽问题是在甚麽地方指明了这个机制呢?我猜这不是因为这是一个内部细节。

如果有任何帮助的话,这应该显示这些行为的合并。

代码语言:javascript
复制
$ bar() { echo automatic; }; export -f bar
$ declare -x foo='() { echo manual; }'
$ declare -p foo bar
declare -x foo="() { echo manual; }"
-bash: declare: bar: not found
$ type foo bar
-bash: type: foo: not found
bar is a function
bar ()
{
    echo automatic
}
$ bash -c 'type foo bar'
foo is a function
foo ()
{
    echo manual
}
bar is a function
bar ()
{
    echo automatic
}
票数 0
EN

Stack Overflow用户

发布于 2014-09-24 20:31:57

你的问题的答案直接来自man bash

exportdeclare -x命令允许将参数和函数添加到环境中并从环境中删除。如果修改了环境中参数的值,则新值将成为环境的一部分,替换旧的.

因此

代码语言:javascript
复制
declare -x date='() { echo today; }'

替换环境中的。下一次对date的直接调用会给出date,因为它存在于脚本中(没有变化)。对bash -c "date"的调用将创建一个新的shell并执行由declare -x定义的日期。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26025442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档