Section outline

  • 为了遵循最小权限原则,Set-UID 程序通常会在不再需要权限时永久放弃其 root 权限。此外,有时程序需要将控制权移交给用户,所以在交权之前,Set-UID 程序会放弃 root 权限。我们可以使用 Set-UID() 系统调用来撤销权限。Set-UID() 设置调用进程的有效用户 ID,但如果调用者的有效 UID 为 root,则实际 UID 和保存的 set-user-ID 也会被设置。因此,如果具有有效 UID=0 的 Set-UID 程序调用 Set-UID(N),则进程将成为普通进程,其所有 UID 都将被设置为 N。

    在撤销权限时,一个常见的错误是权限泄漏。进程在仍具有权限时可能已经获得了一些特权功能。当权限被降级时,如果程序没有清除这些功能,它们可能仍然可以被非特权进程访问。换句话说,尽管进程的有效用户 ID 已变为非特权用户,但进程仍可能拥有特权。

    编译以下程序,将其所有者更改为 root,并使其成为一个 Set-UID 程序。以普通用户身份运行该程序。你能利用该程序中的权限泄漏漏洞吗?你的目标是做到能够以普通用户的身份修改 /etc/zzz 文件。

    void main()
    {
      int fd;
      char *v[2];
    
      /* 假设 /etc/zzz 是一个重要的系统文件,
       * 并且它的所有者是 root,权限是 0644。
       * 在运行此程序之前,你应先创建 /etc/zzz 文件。 */
      fd = open("/etc/zzz", O_RDWR | O_APPEND);
      if (fd == -1) {
         printf("Cannot open /etc/zzz\n");
         exit(0);
      }
    
      // 打印文件描述符值
      printf("fd is %d\n", fd);
    
      // 通过将有效 uid 设置为与实际 uid 相同来永久放弃特权
      setuid(getuid());
    
      // 执行 /bin/sh
      v[0] = "/bin/sh"; v[1] = 0;
      execve(v[0], v, 0);
    }