标记应执行的文件

标记应执行的文件

阅读时,我发现了以下漏洞:

% cp /usr/bin/id ~
% chmod -x ~/id
% ls -al ~/id
-rw-r--r-- 1 edd edd 22020 2012-08-01 15:06 /home/edd/id
% ~/id
zsh: permission denied: /home/edd/id
% /lib/ld-linux.so.2 ~/id
uid=1001(edd) gid=1001(edd) groups=1001(edd),1002(wheel)

此代码片段表明,我们可以以普通非特权用户的身份轻松绕过文件系统的执行权限。我在 Ubuntu 12.04 上运行了此代码。

虽然根据 file(1),Linux 加载程序是一个共享对象,但它也有一个允许直接执行的入口点。当以这种方式执行时,Linux 加载程序充当 ELF 二进制文件的解释器。

但是,在我的 OpenBSD 机器上,此漏洞无效,因为您可能无法将加载程序作为程序执行。OpenBSD 手册页说:“ld.so 本身是一个共享对象,最初由内核加载。”。

在 Solaris 9 上尝试此操作,您将得到一个段错误。我不确定其他地方会发生什么。

我的问题是:

  • 为什么 Linux 加载程序(直接执行时)不是在解释 ELF 二进制文件之前检查文件系统属性?
  • 如果可以轻易绕过,为什么要实施禁止执行文件的机制?我是不是漏掉了什么?

答案1

许可的目的execute不是阻止执行一般来说。它(1)告诉程序哪些文件需要执行,(2)阻止执行作为特权用户,当指定 setuid 位(等等)时。

链接器攻击并不像看上去那么容易。你可以更轻松地执行任何你有权读取的不可执行文件:

$ cp unexecutable_file ~/runme
$ chmod +x ~/runme
$ ~/runme

Arch Linux 论坛上的这个讨论

总之:

标记应执行的文件

当你编写一个 shell 脚本时,你可以用 将其标记为可执行文件chmod +x。这向你的 shell 暗示你希望它是可执行的(否则对于所有 shell 来说,它只是另一个纯文本文件)。然后,当你输入 时,shell 可以在制表符补全中显示它./Tab

类似地:something.d目录(例如init.d)包含通常由守护进程自动执行的启动或控制 shell 脚本。您可能希望将注释或 README 文件作为纯文本文件放在目录中。或者您可能希望暂时禁用其中一个脚本。您可以通过清除该特定文件的执行位来实现这一点。这会告诉守护进程跳过它。

防止特权执行

setuid的意思是当你执行该文件时,是以指定的用户身份(例如root)执行的。

论坛帖子解释得很好:

您希望某个可执行文件对某些用户具有 setuid 权限,但您只希望特定组中的用户能够以 setuid 权限执行该文件。他们仍然可以通过复制来执行该文件,但 setuid 标志会丢失,因此他们将以自己的身份执行该文件,而不是以拥有原始文件的用户身份执行该文件。

答案2

如果您具有某个文件的读取权限,那么您可以随时复制它。

如果您可以制作个人副本,则您可以始终将该副本标记为可执行文件。

这并不能解释 ld-linux 的行为但确实表明它可能不是一个非常有用的安全漏洞。

如果您想要更严格的安全性,请考虑SELinux

答案3

换个角度来看这个问题:正如 Mechanical Snail 所说,文件的执行权限并非旨在阻止执行。但是,文件系统选项“noexec”确实会阻止执行,而且不容易被绕过(并非所有文件系统都支持,但最流行的 Linux 文件系统肯定支持)。如果管理员想阻止用户运行自己的程序,他们可以在主目录和 tmp 目录以及用户可能创建文件的任何其他目录中指定 noexec 选项。

$ mount -o noexec /dev/sdd1 /test
$ cd /test
$ cp /usr/bin/id .
$ ./id
-bash: ./id: Permission denied

显然,过去可以使用问题中提到的加载器技巧来绕过 noexec 选项,但是该问题在几个版本之前的内核中已得到修复。

http://linux.die.net/man/8/mount

禁止执行

不允许在已挂载的文件系统上直接执行任何二进制文件。(直到最近,仍然可以使用 /lib/ld*.so /mnt/binary 之类的命令来运行二进制文件。此技巧自 Linux 2.4.25 / 2.6.0 起失效。)

相关内容