为什么在环境变量中定义功能的能力本身不是安全风险?


9

据我了解,通常认为让任何人提供将存储在环境变量中的信息都是安全的。shellshock漏洞在这里是一个问题,因为这意味着当新的bash实例启动并且您显然不希望任何人在您的服务器上运行他们喜欢的任何代码时,将在环境变量中的函数定义末尾执行代码。尽管函数定义本身显然没有安全风险,但允许使用,因为必须明确调用它们才能执行代码。

我的问题是,为什么恶意用户不能简单地定义一个函数,将其恶意代码作为通用命令包含在其中ls,然后希望脚本(或正在运行的任何东西)在某个时候使用该命令?

我想到的一个例子:

$ export ls='() { echo "doing bad things..."; }'
$ bash -c ls
doing bad things...

Answers:


10

这是安全隐患。这通常就是为什么在切换到另一个上下文(系统的远程控制,更改用户等)时无法执行此操作的原因。

如果您具有创建所需的任何环境变量的能力,则可以使用多种潜在方法来执行任意代码。
$LD_PRELOAD作为一个例子。如果您能够设置该变量,则可以替换库函数,并将代码粘贴在其中。您可以设置$DISPLAY变量,并重定向程序连接到的X显示,以便您可以控制应用程序。

这就是为什么诸如此类sudo的东西会剥夺所有变量的环境。sudo只允许几个选择变量通过。在这些变量中,它对它们进行了消毒(它通过$TERM变量,但是如果包含不寻常的字符则不会)。


哇,我一直想知道为什么我在BASH中执行的一些大型脚本在以sudo启动时会产生奇怪的奥术失败,尤其是在路径周围,这导致我检查sudo启动并阻止了它们,但是我不知道为什么会这样并且是一个问题,感谢您的良好解释。sudo去除了环境变量。
Lizardx '16

3

我想说的是,当bash是您的/ bin / sh时。它不是bourne shell的功能,我敢打赌,它也不是posix shell的功能,实际上,他们可能想明确禁止它。

尽管Bash具有其名称,并且实际上是唯一具有此功能的类似Korn的外壳,但Bash实际上更像是Korn衍生外壳,而不是bourne外壳,在我看来,Bash是没有实际优点的厨具功能。避免使用标准bash功能的开发人员,例如bourne shell,posix shell或现代shell共同拥有的ksh88子集,或者换句话说,他们致力于良好实践和标准习惯用法,当他们使用软件时,会感到震惊linux和mac以及现在可能容易受到攻击的漏洞,因为漏洞利用者可以自由使用“ bashism”,尽管有其意图。就/ bin / sh而言,与其他korn shell派生类相比,在改善兼容性方面,只有/ bin / sh是您的登录shell或交互式shell,而bash的行为更像bourne shell,而不是korn shell,

我会尝试说服您使用厨房水槽功能,有两种情况:您是嵌入式开发人员,负责制造路由器,网络连接存储第一个更大的环境等设备,意味着更多的内存,更多的成本,如此少的利润,因此,如果这是考虑使用bash的此功能的原因,您是否应该改为使用FPATH和autoload和ksh88功能呢?而不是在环境中逐字节传递整个功能字节?您甚至可以考虑对环境进行解析和修剪,然后再获取可能无法解析变量的shellscript,例如仅过滤掉^ $(。*)$等。

这确实强调了这一点的独特之处,无论变量是什么,脚本都不必引用或使用变量,它仍然很容易受到攻击。

#!/bin/sh
exec /usr/local/myapp/support/someperlscript.pl

对于在阳光下的其他所有事物,以上内容应与perl脚本一样安全,您没有使用任何变量,怎么会误解任何变量呢?更改为

#!/bin/bash -norc
exec /usr/local/myapp/support/someperlscript.pl

这也无济于事,这与ENV或类似的东西毫无关系-每个人都被烧死了,因为bash必须是唯一的。对我而言,bash版本2确实存在问题,这一事实证明,没有人在其应用程序中使用过此功能,因为否则它就不会潜伏这么久了。更糟糕的是,基本上没有避免使用此功能。这是一个带有以下示例的示例:使用'su-',如果您要问某人,原因可能是它丢弃了环境,请查看手册页,您只会发现99.9%。我以正确的方式进行了测试,因为在此系统上/ bin / sh是root的登录shell,而/ bin / sh是bash BUT,在此示例中,我尝试强化我的.bash_profile。我将现有名称重命名为root(已启用),但是我的想法是,如果su,然后可能是sudo,无论如何,我更改为:

exec env -i TERM=vt102 LOGNAME=root USER=root HOME=/var/root /bin/ksh -i

因此,我实际上是在完全折腾环境,并使用最小的env,然后运行一个不应该出现问题的shell来代替当前进程。然后代替标准示例尝试:

%dock='() { echo -e "\e[2t\c"; echo dockshock;} ; dock' su 

这说明了它与解析任何特定函数无关,并且利用程序可以引用和使用该函数。您可以想象该函数具有逻辑来测试是否为root等。在这种情况下,它只是一个修改后的函数,使用转义序列来图标化或停靠终端窗口,这很标准,因此在单击去图标化后,看到基座震动-但是,那又如何呢?现在尝试这个:

%TERM='() { echo -e "\e[2t\c"; echo dockshock;} ; TERM' su - 

你猜怎么着?窗户被吸进了码头。这是之后的样子。

%TERM='() { echo -e "\e[2t\c"; echo dockshock;} ; TERM' su -
Password:
dockshock
# env
_=/usr/bin/env
HOME=/var/root
LOGNAME=root
TERM=vt102
USER=root
# echo $0
/bin/ksh
#

所以,这很重要!导出的函数实际上优先于rc脚本。你不能躲避它。


1
POSIX允许草案2中的可导出功能,此后不允许它们使用。该功能太疯狂了。
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.