据说在脚本中依赖 $0 是危险的(经常引用伪造它:exec -a ...)。是的,在我有写访问权限的目录中,我可以符号链接到一个脚本来伪造它的 $0。但是如何使 $0 指向我没有写访问权限的路径(例如下面的 /bin/pwd)?
下面,如果我的脚本使用 shebang,我无法实现它。当目标脚本使用shebang时可以完成吗?
$ (exec -a /bin/pwd /tmp/a0.sh)
no-shebang: argv0=/bin/pwd /proc/.../cmdline=/bin/bash^@--noediting^@-i^@
$ (exec -a /bin/pwd /tmp/a1.sh)
yes-shebang: argv0=/tmp/a1.sh /proc/.../cmdline=/bin/sh^@/tmp/a1.sh^@
$ head /tmp/a0.sh /tmp/a1.sh
==> /tmp/a0.sh <==
echo no-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
==> /tmp/a1.sh <==
#!/bin/sh
echo yes-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
也就是说,如果一个脚本(及其父目录)是写保护的,并且使用了 shebang,那么它对 $0 的使用是安全的(防止伪造另一个写保护的路径)?
这里使用(在 centos 7 上)bash 的 exec 语句作为 $0 的简单伪造。使用 execve() 的 C 程序不会有所不同吗?是否未能在 execve() 下游(在内核或 shebang-target 中)伪造它,而不是 bash 的 exec 太弱?
编辑:C 中的 execve() 也不会在 shebang 情况下伪造 $0,输出与上面相同:
#include <stdio.h>
int main(void) {
char* argv[] = { "/bin/pwd", NULL };
execve("/tmp/a1.sh", argv, NULL);
perror(NULL);
}
我知道如果用户获得 root 权限,那么假 $0 是你的问题。但是我的带有shebang的写保护脚本不能被非root用户伪造$ 0(到另一个写保护路径):$ 0('just use exec -a ...')的危险似乎是错误的。
好吧,手册
execve(2)
页说:因此,当您运行时
exec -a /bin/pwd /tmp/a1.sh
,系统会运行/bin/sh /tmp/a1.sh
,并且当这样启动时,shell$0
会从脚本文件的名称中设置。shell 获得的值
argv[0]
不会出现,例如exec -a foobar /bin/sh /tmp/a1.sh
仍会显示/tmp/a1.sh
在 中$0
,并且从 的内容来看/proc/.../cmdline
,运行脚本时设置的值似乎无论如何都会丢失。但这并不意味着脚本看到的值
$0
不能被伪造:用户可以对脚本创建符号链接并通过链接调用它,或者执行以下操作:那将设置
$0
为foobar
,然后简单地输入/tmp/a1.sh
。