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/>