这是我用来检查我的 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”打印出来。或者,攻击者可以做的不仅仅是打印东西。