是否记录了Bash中的Shellshock漏洞背后的行为或者是故意的?

koj*_*iro 56 security bash function environment-variables shellshock-bash-bug

最近披露Bash如何解释环境变量的漏洞CVE-2014-6271.该漏洞依赖于Bash将一些环境变量声明解析为函数定义,但随后继续按照定义执行代码:

$ x='() { echo i do nothing; }; echo vulnerable' bash -c ':'
vulnerable
Run Code Online (Sandbox Code Playgroud)

但我不明白.我在Bash手册中找不到任何关于将环境变量解释为函数的内容(除了继承函数,这是不同的).实际上,正确命名的函数定义只被视为一个值:

$ x='y() { :; }' bash -c 'echo $x'
y() { :; }
Run Code Online (Sandbox Code Playgroud)

但腐败的人什么都不打印:

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

$ # Nothing but newline
Run Code Online (Sandbox Code Playgroud)

损坏的函数是未命名的,因此我不能只调用它.这个漏洞是一个纯粹的实现错误,还是这里有一个预期的功能,我看不到?

更新

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

$ n='() { echo wat; }' bash -c 'n'
wat
Run Code Online (Sandbox Code Playgroud)

我之前发誓我可以发誓,但我想我没有努力.它现在可以重复了.这是一个更多的测试:

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

wat
Run Code Online (Sandbox Code Playgroud)

...显然,在攻击执行时没有设置args.

无论如何,我的问题的基本答案是,是的,这是Bash实现继承函数的方式.

Bar*_*mar 49

这似乎是一个实现错误.

显然,导出函数的工作方式bash是使用特殊格式的环境变量.如果导出函数:

f() { ... }
Run Code Online (Sandbox Code Playgroud)

它定义了一个环境变量,如:

f='() { ... }'
Run Code Online (Sandbox Code Playgroud)

可能发生的事情是,当新shell看到一个值开头的环境变量时(),它会预先设置变量名并执行生成的字符串.错误是这包括在函数定义之后执行任何操作.

所描述的修复显然是解析结果,看它是否是一个有效的函数定义.如果不是,则打印有关无效功能定义尝试的警告.

本文确认了我对bug的原因的解释.它还详细介绍了修复程序如何解决它:它们不仅更仔细地解析值,而且用于传递导出函数的变量遵循特殊的命名约定.此命名约定与为CGI脚本创建的环境变量使用的命名约定不同,因此HTTP客户端永远不能进入此门.


jm6*_*666 16

下列:

x='() { echo I do nothing; }; echo vulnerable' bash -c 'typeset -f'
Run Code Online (Sandbox Code Playgroud)

版画

vulnerable
x () 
{ 
    echo I do nothing
}
declare -fx x
Run Code Online (Sandbox Code Playgroud)

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

echo vulnerable

x='() { x; }; echo vulnerable' bash -c 'typeset -f'
Run Code Online (Sandbox Code Playgroud)

打印:

vulnerable
x () 
{ 
    echo I do nothing
}
Run Code Online (Sandbox Code Playgroud)

并运行 x

x='() { x; }; echo Vulnerable' bash -c 'x'
Run Code Online (Sandbox Code Playgroud)

版画

Vulnerable
Segmentation fault: 11
Run Code Online (Sandbox Code Playgroud)

segfaults - 无限递归调用

它不会覆盖已定义的函数

$ x() { echo Something; }
$ declare -fx x
$ x='() { x; }; echo Vulnerable' bash -c 'typeset -f'
Run Code Online (Sandbox Code Playgroud)

打印:

x () 
{ 
    echo Something
}
declare -fx x
Run Code Online (Sandbox Code Playgroud)

例如,x仍然是先前(正确)定义的函数.

对于Bash 4.3.25(1)-release,漏洞已关闭,因此

x='() { echo I do nothing; }; echo Vulnerable' bash -c ':'
Run Code Online (Sandbox Code Playgroud)

版画

bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
Run Code Online (Sandbox Code Playgroud)

但是 - 有什么奇怪的(至少对我而言)

x='() { x; };' bash -c 'typeset -f'
Run Code Online (Sandbox Code Playgroud)

仍然打印

x () 
{ 
    x
}
declare -fx x
Run Code Online (Sandbox Code Playgroud)

x='() { x; };' bash -c 'x'
Run Code Online (Sandbox Code Playgroud)

分段错误也是如此,所以它仍然接受奇怪的函数定义...

  • 您无法以这种方式定义函数,至少不能明确定义.只有继承这种值的`bash`实例才会将它"实例化"为可执行函数.也就是说,使用`export foo ='(){echo 5; '',``foo`将保持当前shell中的正常字符串参数,但是子`bash`会使它成为一个函数(`echo $ foo`将不会打印任何内容,例如,因为没有名为`foo的参数`在孩子身上,只是一个功能). (2认同)

Fat*_*ror 13

我认为值得看看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))
Run Code Online (Sandbox Code Playgroud)

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

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

当新的Bash进程在其环境中找到以这种方式定义的函数时,它将使用变量来评估变量中的代码parse_and_execute().对于普通的非恶意代码,执行它只是在Bash中定义函数并继续.但是,因为它传递给通用执行函数,所以Bash将在函数定义之后正确解析并执行该变量中定义的其他代码.

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