3 提升 Set-UID 程序的安全性

  • exec函数
  • exec函数系列通过将当前进程映像包装为新的,来运行紫禁城。有许多exec函数的版本,工作方式不同。它们可以归类为:
  • 使用/不适用 Shell 来启动新程序。
  • 通过 Shell 处理命令行参数(Shell 可以引入比我们预期的更多功能。要注意 Shell 是个强大程序)。
  • 启动子进程涉及到依赖问题以及属性继承,我们之前看到它可能存在问题。函数execlpexecvp使用 Shell 来启动程序。它们使程序的执行依赖于当前用户安装的 Shell。例如,依赖于PATH和其它环境变量的值。函数execv跟家安全,因为它不向代码引入任何这种依赖。
  • system(CMD)调用向 Shell 传递字符串来执行子进程(即作为单独派生的进程)。它是个用于执行 EXEC 函数的方便的前端。
  • popen的标准实现也与之相似。这个函数打开到新锦成管道,以便执行命令,并读取任何输出作为文件流。这个函数也启动 Shell 来解释命令字符串。
  • 如何安全地调用程序?
  • 避免任何 Shell 的调用。不使用system,而是execveexecve不调用 Shell,system调用。
  • 避免execlp (file, ...)execvp(file,...),它们的语义类似于 Shell。它们使用文件内存作为 Shell 的标准输入,如果文件不是有效的可执行目标文件。
  • 小心可能使用 Shell 实现的函数。
  • Perl 的open函数可以执行命令,通常通过 Shell 来这么做。
  • 提升system的安全性
  • 要记住system首先调用/bin/sh。在 Ubuntu 中,它使用参数sh, -c和用户提供的字符串来调用execv /bin/sh
  • 在一些 Ubuntu 的早起版本中(例如 9.11),/bin/sh(实际上是 Bash)忽略 Set-UID 位选项。因此,在 Set-UID 中调用system(CMD)时,CMD 不会使用 Root 权限执行,除非 CMD 本身也是个 Set-UID 程序。下面 代码在 Bash 中丢弃了 Set-UID 位。
if (running_setuid && privileged_mode == 0) 
    disable_priv_mode ();

... 
void disable_priv_mode () { 
    setuid (current_user.uid);
    setgid (current_user.gid); 
    current_user.euid = current_user.uid; 
    current_user.egid = current_user.gid;
}
  • 但是,上面的保护看似破坏了一些需要使用system的 Set-UID 程序。因此,从某个版本起,由于添加了其它条件(对于 11.04 和 12.04),保护被移除了。
if (running_setuid && privileged_mode == 0 && act_like_sh ==0) 
    disable_priv_mode ();

如果 Bash 通过/bin/sh符号链接调用,act_like_sh设为 1,因此权限没有禁用。但是,如果你直接将 Bash 变成 Set-UID 程序并尝试运行,保护仍然会有效,并且权限会丢弃。