我以 root 用户身份登录到终端。
然后在 Python 中:
os.setuid(471)
能够切换到子根,但是当我尝试使用切换回根用户os.setuid(0)
时出现以下错误:Operation not permitted
请让我知道如何从 subroot 切换回 root 用户。
我以 root 用户身份登录到终端。
然后在 Python 中:
os.setuid(471)
能够切换到子根,但是当我尝试使用切换回根用户os.setuid(0)
时出现以下错误:Operation not permitted
请让我知道如何从 subroot 切换回 root 用户。
在子进程中调用os.fork()
并切换到非root用户。“切换回来”只需在子节点中退出并等待子节点在父节点中退出。例如:
pid = os.fork()
if pid == 0:
# child - do the work and exit
try:
os.setuid(471)
... do the work here
finally:
os._exit(0)
# parent - wait for the child to do its work and keep going as root
os.waitpid(pid, 0)
这不是 setuid 的工作方式。当 root 自身降级时,无法重新获得 root 是设计使然。一旦你放弃 root (在这种情况下),它就消失了。
如果您以 root 身份使用 setuid,则无法返回。
我假设 os.setuid 是一个通过 C 级调用的瘦代理。从手册页:
如果用户是 root 或程序是 set-user-ID-root,则必须特别小心。setuid() 函数检查调用者的有效用户 ID,如果它是超级用户,则所有与进程相关的用户 ID 都设置为 uid。发生这种情况后,程序就不可能重新获得 root 权限。
至于为什么无法重新获得root,考虑一个典型的使用。想象一个 Apache 服务器下降到www
(或某种非特权用户)来处理实际请求。如果您可以重新获得 root,Python 脚本(或 PHP/Perl/CGI/等)可以重新获得 root 并造成绝对的破坏。
至于解决方案,您可以改用 seteuid (os.seteuid - 再一次,一个简单的代理到 C 级seteuid)。关于 setuid 和 seteuid 的 python 文档看起来很糟糕,但是有大量关于系统调用的文档。
至于暂时掉根和恢复的安全性......你需要非常小心。如果恶意代码有机会获得根,你就完蛋了。出于这个原因,最好派生一个子进程(正如 user4815162342 所建议的那样)。子进程将无法重新root。可以在此处找到有关这些问题的更多信息。更多关于 setuid 的一般奇怪之处在这里。
这个想法是使用 seteuid 设置有效的用户 ID 并产生一个新进程。由于 exec 的工作方式,有效的用户 id 将被复制到新进程保存的 uid 中。由于保存的 uid 不再是 root,因此无法将 root 改回。更多有趣的文档可以在这里找到。
最相关的部分:
如果在 filename 指向的程序文件上设置了 set-user-ID 位,并且底层文件系统没有挂载 nosuid(mount(2) 的 MS_NOSUID 标志),并且调用进程没有被 ptrace,那么调用进程的有效用户ID更改为程序文件所有者的有效用户ID。类似地,当设置程序文件的set-group-ID位时,调用进程的有效组ID被设置为程序文件的组。
进程的有效用户ID复制到保存的set-user-ID;类似地,有效组 ID 被复制到保存的 set-group-ID 中。此复制发生在由于 set-user-ID 和 set-group-ID 权限位而发生的任何有效 ID 更改之后。
Use seteuid() instead to set the effective ID but maintain the privilege:
import os
os.seteuid(471)
...
os.seteuid(os.getuid())