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)
分段错误也是如此,所以它仍然接受奇怪的函数定义...
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定义.