编解码器正在做它应该做的事情。也许一个过于简单的例子可以更清楚地说明为什么这是正确的行为。
假设您有一个 Web 应用程序,您让用户上传一个文档,然后您为他们运行拼写检查并将更正后的结果发回给他们。为简单起见,我们假设您已将当前工作目录设置为特定于使用您的服务的每个用户,并且您有一个“spellcheck.bat”,它采用单个文件名作为参数,并且您计划执行字符串:
C:\Windows\System32\cmd.exe /c C:\spelling\spellcheck.bat userFilename > spelling-errors.txt
其中 userFilename 是用户上传文件的名称。您的意图是使用用户上传的文件和文件名运行 spellcheck.bat 并读取并显示“spelling-errors.txt”文件给用户。 (IRL,这可能是不同目录中的临时文件,但我想让这个简单。)
如果 'userFilename' 包含 '>' 字符会发生什么?您当然希望适当地引用它,不是吗?因为否则攻击者可能能够覆盖一些您不想被覆盖的文件,包括您的 web.xml 或其他配置/属性文件。因为运行类似(比如说)
C:\Windows\System32\cmd.exe /c C:\spelling\spellcheck.bat myDoc.txt >sucker.txt > spelling-errors.txt
将创建“sucker.txt”,如果该文件名存在,它将被截断并替换为“spellcheck.bat myDoc.txt”的输出。这可能不是你想要的。
因此,旨在通过“”和“>>”来防止文件 I/O 重定向操作。如果你真的想允许它们(我建议不要这样做),那么你将不得不根据你想要允许的内容来解析你自己的命令字符串。
此外,虽然我不确定 Window 的 cmd 提示 shell 是否如此,但对于 *nix shell 来说,作为文件重定向的一部分,也可以在重定向中执行命令执行,这当然是正确的。例如,在 bash 中,我可以做这样的事情
cat < $(ls foo)
如果文件'foo'存在,'ls foo'命令会列出输出的foo,所以这个命令变成:
cat < foo
我们最终只是从文件“foo”中为“cat”命令获取标准输入。但是攻击者可以用它做一些更邪恶的事情。当然,操作系统编解码器也可以防止 '$(...)' 风格的命令替换,但我希望我的意思已经说明了。