据我了解,通常认为让任何人提供将存储在环境变量中的信息是安全的。 shellshock 漏洞是这里的一个问题,因为它意味着当 bash 的新实例启动时,环境变量内函数定义末尾的代码将被执行,并且您显然不希望任何人在您的服务器上运行他们喜欢的任何代码。函数定义本身显然不存在安全风险,并且是允许的,因为必须显式调用它们才能执行其代码。
我的问题是,为什么恶意用户不能简单地定义一个函数,将其恶意代码包含为通用命令,ls
然后希望脚本(或正在运行的任何内容)在某个时候使用此命令?
我的想法的一个例子:
$ export ls='() { echo "doing bad things..."; }'
$ bash -c ls
doing bad things...
答案1
这是一个安全风险。这通常就是为什么在切换到另一个上下文(系统的远程控制、更改用户等)时无法执行此操作的原因。
如果您能够创建所需的任何环境变量,则可以通过多种潜在方式执行任意代码。
举$LD_PRELOAD
个例子。如果您有能力设置该变量,则可以替换库函数,并将代码粘贴到其中。您可以设置该$DISPLAY
变量,并重定向程序连接到的 X 显示,以便您可以控制应用程序。
这就是为什么要sudo
去除所有变量的环境。sudo
只允许少数选择变量通过。对于这些变量,它会清理它们(它会传递变量$TERM
,但如果它包含不寻常的字符,则不会)。
答案2
我想说的是,当 bash 是你的 /bin/sh 时。这不是 bourne shell 的功能,我敢打赌这也不是 posix shell 的功能,事实上他们可能想明确禁止它。
Bash 实际上更像是 korn 衍生 shell,而不是 bourne shell,尽管它的名字如此,并且它是唯一具有该功能的类似 Korn 的 shell,在我看来,它是厨房水槽功能,没有任何实际优点。那些避免使用标准 bash 功能(例如 bourne shell、posix shell 或现代 shell 共有的 ksh88 子集)的开发人员,或者换句话说,致力于良好实践和标准习惯用法的开发人员,当他们的软件启动时会感到震惊linux 和 mac 现在可能容易受到攻击,因为漏洞利用作者可以自由地使用“bashisms”,无论他们的意图如何。就兼容性而言,当作为 /bin/sh 调用时,相对于其他 korn shell 衍生物,只有当 /bin/sh 是您的登录 shell 或交互式 shell 时,bash 的行为更像是 bourne shell,而不是 korn shell,但是当在脚本中使用时,您可以自由地执行 bash 可以执行的任何操作,并且它不会抱怨或警告您正在使用真正的 korn shell 功能或 bash 独有的功能。
我会尝试说服你这是厨房水槽功能,有两种情况:你是一个嵌入式开发人员,制造路由器、网络附加存储等设备第一个更大的环境,意味着更多,内存,所以,更多的成本,所以利润更少,所以,如果这是考虑使用 bash 的此功能的原因,您不应该改用 FPATH 和自动加载、ksh88 功能吗?而不是在环境中逐字节传递整个函数?您甚至可以考虑对环境进行批量解析和修剪,然后再进入可能会错误解析变量的 shell 脚本,例如过滤掉 ^$(.*)$ 等...
这确实强调了它的独特之处,变量是什么并不重要,并且脚本不必引用或使用该变量,它仍然可能容易受到攻击。
#!/bin/sh
exec /usr/local/myapp/support/someperlscript.pl
对于阳光下的其他一切,上面的内容应该和 perl 脚本一样安全,你没有使用任何变量,你怎么可能会错误解析任何变量呢?更改为
#!/bin/bash -norc
exec /usr/local/myapp/support/someperlscript.pl
也没有帮助,这与 ENV 或类似的东西无关——每个人都会被烧伤,因为 bash 需要是唯一的。事实上 bash 版本 2 有这个问题,对我来说证明了这一点从来没有人使用过这个功能对于他们的应用程序,因为否则它应该不是已经潜伏在周围这长的。更糟糕的是基本上无法避免这一点特征。这是一个例子: with 'su -' ,如果你问某人,解释是它会丢弃环境,检查手册页,你会发现只有 99.9% 。我测试了正确的方法,因为在这个系统上 /bin/sh 是 root 的登录 shell,而 /bin/sh 是 bash但,在这个例子中我尝试强化我的 .bash_profile。我将现有的名称重命名为 root (已启用),但我的想法是如果 su,那么可能是 sudo,无论如何,我更改为:
exec env -i TERM=vt102 LOGNAME=root USER=root HOME=/var/root /bin/ksh -i
因此,我实际上完全抛弃了环境,并使用最小的环境,然后运行一个不应该出现问题的 shell 来代替当前进程。然后尝试代替标准示例:
%dock='() { echo -e "\e[2t\c"; echo dockshock;} ; dock' su
这说明它与解析任何特定函数无关,并且漏洞利用可以引用和使用该函数。您可以想象该函数具有测试是否为 root 等的逻辑。在这种情况下,它只是一个修改后的函数,用于图标化或停靠终端窗口,使用转义序列,这是非常标准的,所以在我单击去图标化之后,我参见dockshock——但是,那又怎样呢?现在试试这个:
%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 脚本。你无法躲避它。