如何在 shell 脚本中删除 root 权限?

mir*_*mir 19 root setuid centos shell-script privileges

OpenVPN 中的“--up”选项通常用于路由等。因此它会在 OpenVPN 放弃 root 权限以作为 nobody 运行之前进行处理。但是,我正在调用需要以非特权用户身份运行的 shell 脚本。

我怎么做?我研究了Drop Process Privileges,尤其是多项式和泰勒尔的答案,但我不明白如何实现。我在 Centos 6.5 中工作,并且 suid 被阻止,作为“chmod u+s”和“setuid()”。

有一个 OpenVPN 插件(“openvpn-down-root.so”),它使“--down”选项调用的脚本能够以 root 身份运行。可能有一个等效的,例如“openvpn-up-user.so”,但我还没有找到。

编辑0

根据 Nikola Kotur 的回答,我已经安装了Ian Meyer 的 runit-rpm。尽管 chpst 命令在终端中工作,但在 up 脚本中它失败并显示“找不到命令”。有效的是“sudo chpst”加上设置正确的显示和语言。请参阅为什么我的终端不能正确输出 unicode 字符?鉴于此,up 脚本需要以下四行:

LANG="en_US.UTF-8"; export LANG
GDM_LANG="en_US.UTF-8"; export GDM_LANG
DISPLAY=:0; export DISPLAY
sudo chpst -u user -U user /home/user/unprivileged.sh &
Run Code Online (Sandbox Code Playgroud)

编辑1

根据 0xC0000022L 的评论,我发现“sudo -u user”和“sudo chpst -u user -U user”一样有效:

LANG="en_US.UTF-8"; export LANG
GDM_LANG="en_US.UTF-8"; export GDM_LANG
DISPLAY=:0; export DISPLAY
sudo -u user /home/user/unprivileged.sh &
Run Code Online (Sandbox Code Playgroud)

我会研究 man sudoers 并更新是否/当我让 sudo 独自工作时。

Jde*_*eBP 20

只覆盖 runit 和 sudo 会错过很多。实际上有一整套工具集,例如 runit,以及用于执行此操作的各种工具,它们的设计目的正是为了:

  • Daniel J. Bernstein 的 daemontools 有setuidgid
    设置标识符 用户/home/用户/unprivileged.sh
  • util-linux(默认安装在较新的 Debian 上)具有setpriv
    setpriv --reuid=用户--regid= --init-groups --inh-caps=-all /home/ user /unprivileged.sh
  • Adam Sampson 的 freedt 有setuidgid
    setuidgid用户/home/用户/unprivileged.sh
  • Bruce Guenter 的 daemontools-encore 有setuidgid
    setuidgid用户/home/用户/unprivileged.sh
  • Gerrit Pape 的 runit 有 chpst
    chpst -u用户/home/用户/unprivileged.sh
  • 韦恩马歇尔的 perp 有runuid
    runuid用户/home/用户/unprivileged.sh
  • Laurent Bercot 的 s6 有s6-setuidgid
    s6-setuidgid用户/home/用户/unprivileged.sh
  • 我的点心有setuidgid
    setuidgid用户/home/用户/unprivileged.sh

它们不会混入添加权限的不同任务,也不会陷入交互模式。

顺便说一下,您的附加问题只不过是您忘记拥有sbin以及bin在您PATH的 .

进一步阅读


小智 7

我将runitchpst工具用于此类任务。例如,从 up 脚本调用您的非特权脚本:

chpst -u nobody /path/to/script
Run Code Online (Sandbox Code Playgroud)


dco*_*les 6

在基于 Linux 的系统上,您可以setpriv(从util-linux):

setpriv --reuid=1000 --regid=1000 --init-groups COMMAND [ARGUMENTS...]  # Like su/runuser/sudo
setpriv --reuid=1000 --regid=1000 --clear-groups COMMAND [ARGUMENTS...]  # Like daemontools setuid(8)
Run Code Online (Sandbox Code Playgroud)

使用runuser如果需要PAM会话(也来自util-linux)

runuser -u USER [--] COMMAND [ARGUMENTS...]
Run Code Online (Sandbox Code Playgroud)

su手册页:

su主要是为非特权用户设计的,特权用户(例如由 root 执行的脚本)的推荐解决方案是使用不需要身份验证并提供单独 PAM 配置的non-set-user-ID 命令runuser(1)。如果根本不需要 PAM 会话,那么推荐的解决方案是使用命令setpriv(1)


小智 5

删除特权并运行其他脚本的脚本(但在这里我只是让它自己运行):

#!/bin/sh

id=`id -u`
safeuser="nobody"

if [ $id = "0" ]
then
         # we're root. dangerous!
        sudo -u $safeuser "$0"      # Be sure to quote "$0"
else
    echo "I'm not root"
    id
fi
Run Code Online (Sandbox Code Playgroud)

例子:

root@n3:/tmp/x# id
uid=0(root) gid=0(root) ??????=0(root)
root@n3:/tmp/x# ./drop.sh
I'm not root
uid=65534(nobody) gid=65534(nogroup) ??????=65534(nogroup)
Run Code Online (Sandbox Code Playgroud)

  • ...如果你的脚本的`$0` 是`/directory/name with space/script`(记住,用户可以在他们拥有的位置创建任意符号链接,即使他们*不*使用`exec -a somename yourscript`用`somename` 的`$0` 调用`yourscript`),然后你会得到`sudo -u nobody /directory/name with space`,`with` 和`spaces` 作为单独的参数传递给你的命令。 (2认同)