下面是我用来检查 bash shell 中是否存在 Shellshock 错误的命令:
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
有人可以详细解释一下这个命令吗?
答案1
这个答案是原文刊登于 Fedora Magazine作者:Matthew Miller,许可:知识共享署名-相同方式共享 4.0执照。
让我解释:
env x='() { :;}; echo OOPS' bash -c :
这将在易受攻击的系统上打印“OOPS”,但如果 bash 已修补,则会默默退出。
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
这将在易受攻击的系统上打印“OOPS”,但“this is a test”
如果 bash 已被修补,则会打印。
您可能听说过它与环境变量有关。但是,为什么环境变量中的代码会被执行呢?嗯,它不应该被执行——但是,由于一个我认为有点过于聪明的功能,它存在一些缺陷。Bash 就是您所看到的终端提示符,但它也是一种脚本语言,并且能够定义函数。您可以像这样执行此操作:
$ Ubuntu() { echo "Ubuntu is awesome."; }
然后你就有了一个新命令。请记住,这里echo
实际上还没有运行;它只是保存了我们运行新命令时将发生的情况。这在一分钟后会很重要!
$ Ubuntu
Ubuntu is awesome.
有用!但是,假设出于某种原因,我们需要执行一个新的 bash 实例作为子进程,并希望在该实例下运行我出色的新命令。该语句的bash -c somecommand
作用正是:在新 shell 中运行给定的命令:
$ bash -c Ubuntu
bash: Ubuntu: command not found
哦,真可惜。子进程没有继承函数定义。但是,它继承了环境——从 shell 导出的键值对集合。(这是一个全新的概念;如果你不熟悉这个概念,现在请相信我。)而且,事实证明,bash 也可以导出函数。所以:
$ export -f Ubuntu
$ bash -c Ubuntu
Ubuntu is awesome.
这一切都很好——只是实现这一点的机制是有点不可靠。基本上,由于 Linux/Unix 没有在环境变量中执行函数的魔法,因此导出函数实际上只是创建一个包含函数定义的常规环境变量。然后,当第二个 shell 读取“传入”环境并遇到内容看起来像函数的变量时,它会对其进行评估。
从理论上来说,这是万无一失因为,记住,定义一个函数实际上并不执行它。除了——这也是我们来这里的原因——代码中有一个错误,当到达函数定义的末尾时,求值并没有停止。它只是继续下去。
当存储在环境变量中的函数合法地创建时,这种情况永远不会发生export -f
。但是,为什么要合法呢?攻击者可以编写任何旧的环境变量,如果它看起来像一个函数,新的 bash shell 就会认为它是!
因此,在我们的第一个例子中:
env x='() { :;}; echo OOPS' bash -c "echo this is a test"
该env
命令使用给定的变量集运行命令。在本例中,我们将其设置x
为看起来像函数的东西。该函数只是一个:
,实际上是一个简单的命令,它被定义为不执行任何操作。但是,在semi-colon
表示函数定义结束的后面,有一个echo
命令。它不应该在那里,但没有什么可以阻止我们这样做。
然后,在这个新环境中运行的命令是一个新的 bash shell,再次带有“ echo this is a test
”或“不执行任何操作:
”命令,之后它将退出,完全无害。
但是 — 哎呀!当新 shell 启动并读取环境时,它会获取变量x
,由于它看起来像一个函数,因此它会对其进行求值。函数定义被无害地加载 — 然后我们的恶意负载也会被触发。因此,如果您在易受攻击的系统上运行上述代码,您将收到“OOPS”
打印结果。或者,攻击者可以做的比打印结果更糟糕。
答案2
在未打补丁的版本bash
它将导出的函数定义存储为环境变量。
将函数存储x
为,
$ x() { bar; }
$ export -f x
并检查其定义如下,
$ env | grep -A1 x
x=() { bar
}
因此,人们可以通过定义自己的环境变量来利用这一点,并将它们解释为函数定义。例如,env x='() { :;}'
将被视为
x() { :;
}
检查 shellshock 的命令有什么作用,
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
从man env
,
env
- 在修改后的环境中运行程序。:
不执行任何操作,仅以退出状态退出0
。请参阅更多的当未打补丁的 bash 的新实例以 启动时
bash -c "echo this is a test"
,精心设计的环境变量将被视为函数并加载。因此,可以得到输出
易受伤害的 这是一个测试
笔记:在 bash 启动期间,函数定义之外的 echo 被意外执行。函数定义只是使求值和利用发生的一个步骤,函数定义本身和使用的环境变量都是任意的。shell 查看环境变量,看到 x,它看起来符合它所知道的函数定义的约束,并且它求值该行,无意中也执行了 echo(可能是任何命令,无论是否恶意)。另请参阅这