Bash 中的 Shellshock 漏洞背后的行为是记录在案还是有意为之?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26022248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is the behavior behind the Shellshock vulnerability in Bash documented or at all intentional?
提问by kojiro
A recent vulnerability, CVE-2014-6271, in how Bashinterprets environment variables was disclosed. The exploit relies on Bash parsing some environment variable declarations as function definitions, but then continuing to execute code following the definition:
最近披露了Bash如何解释环境变量的漏洞CVE-2014-6271。该漏洞利用 Bash 将一些环境变量声明解析为函数定义,然后继续执行定义后的代码:
$ x='() { echo i do nothing; }; echo vulnerable' bash -c ':'
vulnerable
But I don't get it. There's nothing I've been able to find in the Bash manual about interpreting environment variables as functions at all (except for inheriting functions, which is different). Indeed, a proper named function definition is just treated as a value:
但我不明白。我在 Bash 手册中找不到任何关于将环境变量解释为函数的内容(除了继承函数,这是不同的)。实际上,正确命名的函数定义只是被视为一个值:
$ x='y() { :; }' bash -c 'echo $x'
y() { :; }
But a corrupt one prints nothing:
但是一个腐败的人什么也不打印:
$ x='() { :; }' bash -c 'echo $x'
$ # Nothing but newline
The corrupt function is unnamed, and so I can't just call it. Is this vulnerability a pure implementation bug, or is there an intended feature here, that I just can't see?
损坏的函数是未命名的,所以我不能直接调用它。这个漏洞是一个纯粹的实现错误,还是这里有一个我看不到的预期功能?
Update
更新
Per Barmar's comment, I hypothesized the name of the function was the parameter name:
根据 Barmar 的评论,我假设函数的名称是参数名称:
$ n='() { echo wat; }' bash -c 'n'
wat
Which I could swear I tried before, but I guess I didn't try hard enough. It's repeatable now. Here's a little more testing:
我可以发誓我以前尝试过,但我想我没有足够努力。现在可以重复了。这里有更多的测试:
$ env n='() { echo wat; }; echo vuln' bash -c 'n'
vuln
wat
$ env n='() { echo wat; }; echo ' bash -c 'n 2' 3 -- 4
wat
…so apparently the args are not set at the time the exploit executes.
...所以显然在漏洞利用执行时没有设置参数。
Anyway, the basic answer to my question is, yes, this is how Bash implements inherited functions.
无论如何,我的问题的基本答案是,是的,这就是 Bash 实现继承函数的方式。
采纳答案by Barmar
This seems like an implementation bug.
这似乎是一个实现错误。
Apparently, the way exported functions work in bash
is that they use specially-formatted environment variables. If you export a function:
显然,导出函数的工作方式bash
是它们使用特殊格式的环境变量。如果导出函数:
f() { ... }
it defines an environment variable like:
它定义了一个环境变量,如:
f='() { ... }'
What's probably happening is that when the new shell sees an environment variable whose value begins with ()
, it prepends the variable name and executes the resulting string. The bug is that this includes executing anything afterthe function definition as well.
可能发生的情况是,当新 shell 看到一个值以 开头的环境变量时()
,它会在变量名之前添加并执行结果字符串。错误在于这也包括在函数定义之后执行任何内容。
The fix described is apparently to parse the result to see if it's a valid function definition. If not, it prints the warning about the invalid function definition attempt.
所描述的修复显然是为了解析结果以查看它是否是有效的函数定义。如果不是,它会打印有关无效函数定义尝试的警告。
This articleconfirms my explanation of the cause of the bug. It also goes into a little more detail about how the fix resolves it: not only do they parse the values more carefully, but variables that are used to pass exported functions follow a special naming convention. This naming convention is different from that used for the environment variables created for CGI scripts, so an HTTP client should never be able to get its foot into this door.
这篇文章证实了我对错误原因的解释。它还详细介绍了修复程序如何解决它:它们不仅更仔细地解析值,而且用于传递导出函数的变量遵循特殊的命名约定。这种命名约定与为 CGI 脚本创建的环境变量所使用的命名约定不同,因此 HTTP 客户端应该永远无法踏入这扇门。
回答by jm666
The following:
下列:
x='() { echo I do nothing; }; echo vulnerable' bash -c 'typeset -f'
prints
印刷
vulnerable
x ()
{
echo I do nothing
}
declare -fx x
seems, than Bash, after having parsed the x=...
, discovered it as a function, exported it, saw the declare -fx x
and allowed the execution of the command after the declaration.
似乎,比起 Bash,在解析了 之后x=...
,发现它作为一个函数,导出它,看到了declare -fx x
并允许在声明后执行命令。
echo vulnerable
echo vulnerable
x='() { x; }; echo vulnerable' bash -c 'typeset -f'
prints:
印刷:
vulnerable
x ()
{
echo I do nothing
}
and running the x
并运行 x
x='() { x; }; echo Vulnerable' bash -c 'x'
prints
印刷
Vulnerable
Segmentation fault: 11
segfaults - infinite recursive calls
段错误 - 无限递归调用
It doesn't overrides already defined function
它不会覆盖已经定义的函数
$ x() { echo Something; }
$ declare -fx x
$ x='() { x; }; echo Vulnerable' bash -c 'typeset -f'
prints:
印刷:
x ()
{
echo Something
}
declare -fx x
e.g. the x remains the previously (correctly) defined function.
例如,x 仍然是先前(正确)定义的函数。
For the Bash 4.3.25(1)-release
the vulnerability is closed, so
对于 Bash,4.3.25(1)-release
该漏洞已关闭,因此
x='() { echo I do nothing; }; echo Vulnerable' bash -c ':'
prints
印刷
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
but - what is strange(at least for me)
但是 - 有什么奇怪的(至少对我来说)
x='() { x; };' bash -c 'typeset -f'
STILL PRINTS
静态打印
x ()
{
x
}
declare -fx x
and the
和
x='() { x; };' bash -c 'x'
segmentation faults too, so it STILL accept the strange function definition...
分段错误也是如此,所以它仍然接受奇怪的函数定义......
回答by FatalError
I think it's worth looking at the Bash code itself. The patchgives a bit of insight as to the problem. In particular,
我认为值得查看 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] = '$ foo() { echo 'hello world'; }
$ export -f foo
$ cat /proc/self/environ | tr '[ 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 [email protected]
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/>
' '\n' | grep -A1 foo
foo=() { echo 'hello world'
}
';
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))
When Bash exports a function, it shows up as an environment variable, for example:
当 Bash 导出一个函数时,它会显示为一个环境变量,例如:
[ 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 [email protected]
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/>
When a new Bash process finds a function defined this way in its environment, it evalutes the code in the variable using parse_and_execute()
. For normal, non-malicious code, executing it simply defines the function in Bash and moves on. However, because it's passed to a generic execution function, Bash will correctly parse and execute additional codedefined in that variable after the function definition.
当一个新的 Bash 进程在它的环境中找到一个以这种方式定义的函数时,它会使用parse_and_execute()
. 对于正常的非恶意代码,执行它只是在 Bash 中定义函数并继续。但是,因为它被传递给一个通用的执行函数,所以 Bash 会在函数定义之后正确解析和执行该变量中定义的附加代码。
You can see that in the new code, a flag called SEVAL_ONECMD
has been added that tells Bash to only evaluate the first command (that is, the function definition) and SEVAL_FUNCDEF
to only allow functio0n definitions.
您可以看到在新代码中,SEVAL_ONECMD
添加了一个名为SEVAL_FUNCDEF
call的标志,它告诉 Bash 只计算第一个命令(即函数定义)并且只允许functio0n 定义。
回答by DocSalvager
In regard to your question about documentation, notice here in the commandline documentation for the env
command, that a study of the syntax shows that env
is working as documented.
关于您关于文档的问题,请注意命令的env
命令行文档中的此处,对语法的研究表明它env
按文档工作。
- There are, optionally, 4 possible options
- An optional hyphen as a synonym for
-i
(for backward compatibility I assume) - Zero or more NAME=VALUE pairs. These are the variable assignment(s) which could include function definitions.
- Note that no semicolon (;) is required between or following the assignments.
- The last argument(s) can be a single command followed by its argument(s). It will run with whatever permissions have been granted to the login being used. Security is controlled by restricting permissions on the login user and setting permissions on user-accessible executables such that users other than the executable's owner can only read and execute the program, not alter it.
- 有可选的 4 种可能选项
- 一个可选的连字符作为同义词
-i
(为了向后兼容,我假设) - 零个或多个 NAME=VALUE 对。这些是可能包括函数定义的变量赋值。
- 请注意,赋值之间或后面不需要分号 (;)。
- 最后一个参数可以是单个命令,后跟它的参数。它将以授予正在使用的登录名的任何权限运行。通过限制登录用户的权限和设置用户可访问的可执行文件的权限来控制安全性,这样可执行文件所有者以外的用户只能读取和执行程序,而不能更改它。
##代码##
##代码##