检查shellshock的命令说明

hee*_*ayl 32 bash shellshock

这是我用来检查我的 bash shell 是否存在 Shellshock 错误的命令:

env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
Run Code Online (Sandbox Code Playgroud)

任何人都可以详细解释命令吗?

αғs*_*нιη 45

这个答案是马修米勒在 Fedora 杂志上的一篇原创文章的衍生,根据知识共享署名-相同方式共享 4.0许可证获得许可。

让我解释:

env x='() { :;}; echo OOPS' bash -c :
Run Code Online (Sandbox Code Playgroud)

这将在易受攻击的系统上打印“OOPS”,但如果 bash 已被修补,则会静默退出。

env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Run Code Online (Sandbox Code Playgroud)

这将在易受攻击的系统上打印“OOPS”,但“this is a test”如果 bash 已被修补,则打印。

您可能听说过它与环境变量有关。但是,为什么要执行环境变量中的代码?嗯,它不应该是 - 但是,由于我想称之为有点过于聪明的功能,它有一些缺陷的空间。Bash 是您所看到的终端提示,但它也是一种脚本语言,并且具有定义函数的能力。你这样做:

$ Ubuntu()  { echo "Ubuntu is awesome."; }
Run Code Online (Sandbox Code Playgroud)

然后你有一个新的命令。请记住,echohere 还没有真正运行;它只是保存为我们运行新命令时会发生什么。这将在一分钟内很重要!

$ Ubuntu
 Ubuntu is awesome.
Run Code Online (Sandbox Code Playgroud)

有用!但是,让我们说,出于某种原因,我们需要执行一个新的 bash 实例,作为一个子进程,并希望在其下运行我的新命令。该语句bash -c somecommand正是这样做的:在新的 shell 中运行给定的命令:

$ bash -c Ubuntu
  bash: Ubuntu: command not found
Run Code Online (Sandbox Code Playgroud)

哦。伤心。孩子没有继承函数定义。但是,它确实具有固有的环境——从 shell 导出的一组键值对。(这是一个完整的概念;如果你不熟悉这个,现在相信我。)而且,事实证明,bash 也可以导出函数。所以:

$ export -f Ubuntu
$ bash -c Ubuntu
  Ubuntu is awesome.
Run Code Online (Sandbox Code Playgroud)

这一切都很好——除了实现这一点的机制有点狡猾。基本上,由于在环境变量中执行函数没有 Linux/Unix 魔法,导出函数实际上只是创建一个包含函数定义的常规环境变量。然后,当第二个 shell 读取“传入”环境并遇到一个内容看起来像函数的变量时,它会对其进行评估。

理论上,这是完全安全的,因为请记住,定义一个函数实际上并没有执行它。除了——这就是我们在这里的原因——代码中有一个错误,当到达函数定义的末尾时,评估没有停止。它只是继续前进。

当存储在环境变量中的函数合法地使用export -f. 但是,为什么要合法?攻击者可以随便组成任何旧的环境变量,如果它看起来像一个函数,新的 bash shell 就会认为它是!

所以,在我们的第一个例子中:

env x='() { :;}; echo OOPS' bash -c "echo this is a test"
Run Code Online (Sandbox Code Playgroud)

env命令运行具有给定变量集的命令。在这种情况下,我们设置x的东西看起来像一个函数。该函数只是一个:,它实际上是一个简单的命令,它被定义为什么都不做。但是,在表示semi-colon函数定义结束的之后,有一个echo命令。那不应该在那里,但没有什么可以阻止我们这样做。

然后,在这个新环境中运行的命令是一个新的 bash shell,再次使用“ echo this is a test”或“什么都不做:”命令,之后它将完全无害地退出。

但是——哎呀!当这个新的 shell 启动并读取环境时,它会访问x变量,因为它看起来像一个函数,所以它会对其进行评估。函数定义被无害地加载——然后我们的恶意负载也被触发。因此,如果您在易受攻击的系统上运行上述内容,您将被“OOPS”打印出来。或者,攻击者可以做的不仅仅是打印东西。

  • @DennisWilliamson 是否需要 `env` 取决于运行测试的 shell,而不是被测试的 shell。(这些可能是一样的。即便如此,我们也在测试 bash 如何处理它自己的*环境。)Bourne 风格的 shell 接受 `NAME=value command` 语法;C 风格的 shell(例如,[`csh`](http://manpages.ubuntu.com/manpages/trusty/en/man1/bsd-csh.1.html)、[`tcsh`](http:// manpages.ubuntu.com/manpages/trusty/en/man1/tcsh.1.html)) 不要。因此,使用 `env` 测试更加便携(代价是有时会对其工作方式造成混淆)。 (4认同)
  • 请注意,`env` 不是必需的。您可以使用不带它的命令来获得相同的结果(通过/失败取决于 Bash 是否已更新):`x='() { :;}; echo OOPS' bash -c "echo 这是一个测试"`。这是因为在带有变量赋值的命令之前将该变量及其值传递到命令的(在本例中为`bash -c "..."`)环境中。 (2认同)