该setuid
权限位告诉Linux与业主,而不是执行者的有效用户ID运行程序:
> cat setuid-test.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("%d", geteuid());
return 0;
}
> gcc -o setuid-test setuid-test.c
> ./setuid-test
1000
> sudo chown nobody ./setuid-test; sudo chmod +s ./setuid-test
> ./setuid-test
65534
Run Code Online (Sandbox Code Playgroud)
但是,这仅适用于可执行文件;shell 脚本忽略 setuid 位:
> cat setuid-test2
#!/bin/bash
id -u
> ./setuid-test2
1000
> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2
1000
Run Code Online (Sandbox Code Playgroud)
维基百科说:
由于安全漏洞的可能性增加,许多操作系统在应用于可执行 shell 脚本时会忽略 setuid 属性。
假设我愿意接受这些风险,有没有办法告诉 Linux 将 shell 脚本上的 setuid …
请比较以下两行:
-rws---r-x 1 root root 21872 2009-10-13 21:06 prg1
-rwx---r-x 1 root root 21872 2009-10-13 21:06 prg2
Run Code Online (Sandbox Code Playgroud)
上的 setuid 位prg1
以及“其他”的读取和执行位是否意味着任何用户都可以使用 root 权限运行它?该 prg2
也有读取和执行“其他”,但没有设置setuid位,这是否意味着它仍然可以通过任何用户,但没有root权限运行?
我有一个由普通用户运行时需要 root 权限的进程。显然我可以使用“setuid 位”来完成此操作。在 POSIX 系统上执行此操作的正确方法是什么?
另外,如何使用使用解释器(bash、perl、python、php 等)的脚本执行此操作?
一个巨大的应用程序需要在某个特定时间对需要 root 权限的文件执行少量写入。它不是真正的文件,而是作为文件暴露给 Linux 的硬件接口。
为了避免为整个应用程序授予 root 权限,我编写了一个 bash 脚本来执行关键任务。例如,以下脚本将启用硬件接口的端口 17 作为输出:
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
Run Code Online (Sandbox Code Playgroud)
但是,由于suid
我系统上的 bash 脚本被禁用,我想知道实现这一目标的最佳方法是什么。
使用此处介绍的一些解决方法
sudo
从主应用程序调用脚本,并相应地编辑 sudoers 列表,以避免在调用脚本时需要密码。授予 sudo 权限让我有点不舒服echo
。
只需编写一个 C 程序,使用fprintf
,并将其设置为 suid root。对字符串和文件名进行硬编码,并确保只有 root 可以编辑它。或者从文本文件中读取字符串,同样确保没有人可以编辑该文件。
我没有想到的其他一些解决方案比上面介绍的更安全或更简单?
我对问题中提到的概念比较陌生,从不同来源阅读它们只会使它们更加混乱。所以这是我到目前为止的理解:
当我们获得文件的权限时,它们看起来像这样:
-rwsr-xr-- 1 user1 users 190 Oct 12 14:23 file.bin
Run Code Online (Sandbox Code Playgroud)
我们假设用户user2
谁是该组中users
试图执行file.bin
。如果未设置 setuid 位,则意味着 的 RUID 和 EUIDfile.bin
都等于 的 UID user2
。但是由于设置了 setuid 位,这意味着 RUID 现在等于 的 UID user2
,而 EUID 是文件所有者的 UID,user1
。
我的问题是:
root
?是否root
与所有者具有相同的权限?或者我们是否需要在权限列表中单独的条目root
?我管理一个 Gentoo Hardened box,它使用文件功能来消除对 setuid-root 二进制文件的大部分需求(例如,/bin/ping
有 CAP_NET_RAW 等)。
事实上,我剩下的唯一二进制文件就是这个:
abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ #
Run Code Online (Sandbox Code Playgroud)
如果我删除了 setuid 位,或者重新挂载我的根文件系统nosuid
,sshd 和 GNU Screen 将停止工作,因为它们调用grantpt(3)
了它们的主伪终端,而 glibc 显然会执行这个程序来 chown 和 chmod 下的从伪终端/dev/pts/
,而 GNU Screen 关心这个函数的时间失败。
问题是,手册页grantpt(3)
明确指出,在 Linux 下,devpts
挂载文件系统后,不需要此类帮助程序二进制文件;内核会自动将slave的UID & GID设置为打开的进程的真实UID & GID /dev/ptmx
(通过调用getpt(3)
)。
我编写了一个小示例程序来演示这一点:
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int master; …
Run Code Online (Sandbox Code Playgroud) 我想确保我的程序只能由xyz
使用 root 权限的用户运行。为此,我设置了 setuid 位:
chmod u+s program1.sh
ls -l program1.sh
rwsr-x--- 1 root house 1299 May 15 23:54 program1.sh
Run Code Online (Sandbox Code Playgroud)
此外,我将用户添加xyz
到house
组中,以便只有xyz
root 用户可以运行 program1.sh。
在 program1.sh 中有
id -u
Run Code Online (Sandbox Code Playgroud)
以便它可以向我显示有效 ID。
program1.sh
以 root 身份运行,它显示root
. 但是使用该xyz
帐户运行时,它显示xyz
. 似乎它没有以 root 权限运行。我不知道这里出了什么问题。
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 …
Run Code Online (Sandbox Code Playgroud) 我写了一个程序,调用setuid(0)
和execve("/bin/bash",NULL,NULL)
.
然后我做了 chown root:root a.out && chmod +s a.out
当我执行时,./a.out
我得到一个 root shell。但是,当我这样做时,gdb a.out
它会以普通用户身份启动进程,并启动一个用户 shell。
那么...我可以调试 setuid root 程序吗?
GID实际上是什么意思?
我用谷歌搜索了一下,这就是linux.about.com所说的:
进程的组标识号。有效的组号在
/etc/group
、 和/etc/passwd
文件的 GID 字段中给出。当一个进程启动时,它的 GID 被设置为其父进程的 GID。
我对文件夹的权限目前为 0755
我明白如果我为所有者设置了 UID,它将是 4755
如果我设置了组的 GID,它将是 2755
如果我为其他人设置粘滞位,它将是 1755
setuid ×10
privileges ×4
root ×3
permissions ×2
scripting ×2
security ×2
centos ×1
chmod ×1
debugging ×1
files ×1
gdb ×1
glibc ×1
group ×1
linux ×1
linux-kernel ×1
process ×1
shell ×1
shell-script ×1