我正在制作一个带有 setuid 权限的 Bash 脚本,但它不起作用。所以我在这里找到了我的解决方案:
现在我的脚本工作正常(我用 cpp 重写了它)。
为了满足我对为什么纯 Bash shell 不起作用的好奇心,我阅读了以下链接:http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html(参考这个答案:https://unix.stackexchange.com/a/2910)。在那个网站上,我发现了以下内容:
$ echo \#\!\/bin\/sh > /etc/setuid_script
$ chmod 4755 /etc/setuid_script
$ cd /tmp
$ ln /etc/setuid_script -i
$ PATH=.
$ -i
我不明白第四行,它写着ln /etc/setuid_script -i
。
该命令有什么作用?
我在手册中读到ln
这-i
只是“交互式”标志(询问您是否要覆盖现有文件)。那么为什么ln /etc/setuid_script -i
后面跟着PATH=.
and-i
会让我的 shell 执行/bin/sh -i
呢?
答案1
该代码ln /etc/setuid_script -i
旨在创建指向-i
当前目录中调用的文件的硬链接。如果您使用的是 GNU 工具,您可能需要说ln -- /etc/setuid_script -i
要使其工作。
shell 可以通过 3 种不同的方式获取命令来运行。
- 来自字符串。
sh -c "mkdir /tmp/me"
与标志一起使用-c
。 - 来自一个文件。使用
sh filename
- 在终端中,使用
sh -i
或sh
。
foo
从历史上看,当您有一个名为“从#!/bin/sh
内核开始”的 shell 脚本时,会使用文件名(即 )调用/bin/sh foo
它,告诉它使用第二种读取命令的方式。如果你给它一个文件名,-i
那么内核就会调用/bin/sh -i
,你就会得到第三种方式。
还有竞争条件。这就被利用了。
- 调用系统
exec
调用来启动脚本。 - 内核看到该文件是SUID,并相应地设置进程的权限。
- 内核读取文件的前几个字节以查看它是什么类型的可执行文件,找到
#!/bin/sh
并因此认为它是 /bin/sh 的脚本。 - 攻击者替换了脚本。
- 内核将当前进程替换为/bin/sh。
- /bin/sh 打开文件名并执行命令。
这是经典TOCTTOU(检查时间到使用时间)攻击。步骤 2 中的检查针对的是与步骤 6 中(在 open 调用中)使用的文件不同的文件。
这两个错误现在通常都已得到修复。
答案2
您链接到的文档(http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html)正在描述(可能是)UNIX 系统上的行为ln
,并且您查看了 Linux 系统(或更准确地说是 GNU/Linux)中的手册。 GNU 是这里的相关部分。 GNUln
确实有你提到的选项:
-i, --interactive
prompt whether to remove destinations
然而,这是一个 GNU 扩展,不属于POSIX标准其中仅定义了以下选项标志:
-f
Force existing destination pathnames to be removed to allow the link.
-L
For each source_file operand that names a file of type symbolic link, create a (hard) link to the file referenced by the symbolic link.
-P
For each source_file operand that names a file of type symbolic link, create a (hard) link to the symbolic link itself.
-s
Create symbolic links instead of hard links. If the -s option is specified, the -L and -P options shall be silently ignored.
因此,由于-i
不是 的有效选项ln
,该命令ln /etc/setuid_script -i
实际上会创建一个名为 的硬链接,-i
该链接指向/etc/setuid_script
。接下来,该命令PATH=.
重新定义PATH
变量以仅搜索当前目录中的可执行文件,这意味着将执行当前目录中-i
指定的文件,因为它是 的硬链接,所以将执行脚本。但是,由于这是一个 shell 脚本,因此实际运行的命令将是.-i
/etc/setuid_script
/bin/sh -i