为什么使用-execdir
find 操作组合不安全而使用-exec
却不安全?
当我运行以下命令时,我收到以下提示消息:
/path/to/currentDir/$ find . -type f -name 'partOfFileNames*' -execdir rm -- {} +
find: The current directory is included in the PATH environment variable, which is insecure
in combination with the -execdir action of find. Please remove the current directory
from your $PATH (that is, remove "." or leading or trailing colons)
什么原因可能导致出现此提示?
答案1
您可能会运行错误的程序。有人可能会强迫您运行他们的程序。
该-execdir
操作从包含找到的文件的目录运行您的命令。当$PATH
包含相对路径时,例如.
或任何不以/
是不安全的,-execdir
因为文件所在的目录(或相对于该文件解析的另一个目录)也可能包含与您尝试运行的可执行文件同名的可执行文件。然后,该可能不受信任的可执行文件将被运行。
另一个用户可能会故意利用这一点,让您运行他们的程序,而不是您尝试运行的程序,这可能会造成损害或破坏数据安全。或者,更不常见的是,它可能会导致无意中运行错误的程序,即使没有人试图制造问题。
如果PATH
环境变量中的所有内容都是绝对路径,则不应发生此错误,即使您正在搜索和-execdir
输入的目录是包含在中PATH
。 (我已经检查过这是否有效。)如果您认为您没有任何相关目录$PATH
但仍然收到此错误,请使用包括输出在内的详细信息更新您的问题echo "$PATH"
。
一个具体的例子。
举个可能出错的例子,假设:
- 爱丽丝
.
之所以有这样的能力,$PATH
是因为她希望能够在她想要的任何目录中运行程序cd
,而不必费心在其名称前面加上./
。 - Alice 的敌友 Eve
/home/eve/shared
与 Alice 分享了彼此。 .c
Alice 想要Eve 与她共享的文件的统计信息(行数、单词、字节数) 。
于是 Alice 运行:
find ~eve/shared -name \*.c -execdir wc {} \;
不幸的是,对于 Alice 来说,Eve 已经创建了自己的脚本,将其命名为wc
,将其设置为可执行文件 ( chmod +x
),并将其秘密地放在 下的一个目录中/home/eve/shared
。Eve 的脚本如下所示:
#!/bin/sh
/usr/bin/wc "$@"
do_evil # Eve replaces this command with whatver evil she wishes to do
因此,当 Alice 使用find
with-execdir
运行wc
Eve 共享的文件时,并且它获取与 Eve 的自定义脚本位于同一目录中的文件时wc
,Eve 就会wc
运行——具有 Alice 的所有权限!
(Eve 很狡猾,她让她的wc
脚本充当系统的包装器wc
,这样 Alice 甚至不知道出了什么问题,也就是说do_evil
运行。但是,更简单(以及更复杂)的变化也是可能的。
如何find
防止这种情况发生。
find
防止发生此安全问题-execdir
当$PATH
包含相对目录时拒绝采取行动。
find
根据具体情况提供两种诊断信息。
如果
.
在中$PATH
,那么(正如你所见)它表示:find: The current directory is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove the current directory from your $PATH (that is, remove "." or leading or trailing colons)
.
由于这种情况特别常见,它可能对这种情况有特殊的意义。如果相对路径不是
.
--say,foo
——出现在$PATH
并且你运行find
,-execdir
它说:find: The relative path `foo' is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH
最好$PATH
根本不要有相对路径。
当使用自动更改目录的实用程序时,.
或其他相对路径的风险尤其会增加,这就是为什么在这种情况下不允许您使用的原因。$PATH
find
-execdir
.
但是,在您的 中使用相对路径(尤其是)$PATH
本身就存在风险,最好还是避免。考虑上面示例中的虚构情况。假设find
Alice 不是运行 ,而是简单地cd
s 到~eve/shared/blah
并运行wc *.c
。如果blah
包含 Eve 的wc
脚本,do_evil
以爱丽丝的身份奔跑。
答案2
有非常详细的信息这里. 另一个很好的参考是这里引用第一个参考文献:
选项 -execdir 是 GNU find 中引入的一个更现代的选项,旨在创建更安全的 -exec 版本。它具有与 -exec 相同的语义,但有两个重要的增强功能:
它总是提供文件的绝对路径(在-exec 的情况下,使用文件的相对路径确实很危险)。
除了提供绝对路径之外,它还会检查 PATH 变量的安全性(如果 PATH 环境变量中存在点,则可以从错误的目录中获取可执行文件)
来自第二个参考:
如果当前目录包含在 $PATH 环境变量中,则“-execdir”操作将拒绝执行任何操作。这是必要的,因为“-execdir”在找到文件的同一目录中运行程序 - 通常,这样的目录可能由不受信任的用户写入。出于类似的原因,“-execdir”不允许“{}”出现在要运行的命令的名称中。
答案3
放PATH=/usr/bin
这不是理想的,但它往往可以解决大多数用例,假设find
和要使用的程序(rm
此处)都在该目录中:
PATH=/usr/bin find -execdir rm ...
您可以根据需要添加任何缺失的 PATH。
xargs
和bash -c cd
解决方法
好吧,我放弃了:
find . -type f |
xargs -I '{}' bash -c 'cd "$(dirname "{}")" && pwd && echo "$(basename "{}")"'
sed
解决方法
比以前的解决方法稍微差一点:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" find . -execdir echo '{}' \;
一个测试用例:
[ "$(printf '/a/b::c/d:/e/f\n' | sed -E 's/(^|:)[^\/][^:]*//g')" = '/a/b:/e/f' ] || echo fail
具体来说rename
,您还可以使用一些 Perl regex-fu:https://stackoverflow.com/questions/16541582/finding-multiple-files-recursively-and-renaming-in-linux/54163971#54163971
RTFS 希望破灭
对于那些希望有办法忽略的find
固执己见的人,让我用一些来源来粉碎它:
- https://git.savannah.gnu.org/cgit/findutils.git/tree/find/parser.c?h=v4.6.0#n2847
- https://git.savannah.gnu.org/cgit/findutils.git/tree/find/parser.c?h=v4.6.0#n2944
由此我们看到似乎没有办法关闭路径检查。
它检查的具体规则是:如果 为PATH
空或不以 开头,则失败/
。
答案4
解决方法是在命令前传递自定义 PATH,例如
PATH=/usr/bin find . -type f -name 'partOfFileNames*' -execdir echo rm -- {} +
上述解决方法将阻止加载全局的$PATH
,而是我们自己的。
这是另一个例子(更灵活),假设我们要运行cat
命令:
PATH=$(dirname $(which find)):$(dirname $(which cat)) find /etc -name hosts -execdir cat {} ';'
或者:
PATH=$(dirname $(which cat find) | paste -sd:) find ...
通过运行,$(dirname $(which cat))
我们计算出要运行的命令位于何处。