setuid 不工作

Anm*_*ggi 1 filesystems users setuid permissions

我试图了解如何setuid工作。

所以我做了一个虚拟程序,它只打印当前用户:

#include<bits/stdc++.h>
using namespace std;


int main(){
    cout << system("id -a") << "\n";
    cout << system("whoami")  << "\n";
}
Run Code Online (Sandbox Code Playgroud)

my-binary在用户下编译并创建了可执行文件anmol

-rwxrwxr-x 1 anmol anmol 9972 Feb  1 16:54 my-binary
Run Code Online (Sandbox Code Playgroud)

然后,我setuid使用chmod +s以下选项设置选项:

-rwsrwsr-x 1 anmol anmol 9972 Feb  1 16:54 my-binary
Run Code Online (Sandbox Code Playgroud)

如果我正常执行它,我会得到以下输出:

uid=1000(anmol) gid=1000(anmol) groups=1000(anmol),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),122(sambashare)
anmol
Run Code Online (Sandbox Code Playgroud)

现在,如果我使用 更改为另一个用户su user2,然后执行它,我会得到:

uid=1001(user2) gid=1001(user2) groups=1001(user2)
user2
Run Code Online (Sandbox Code Playgroud)

当我使用 执行它时sudo ./my-binary,我得到:

uid=1001(root) gid=1001(root) groups=1001(root)
root
Run Code Online (Sandbox Code Playgroud)

据我了解,无论我如何运行它,我不应该每次都得到第一个输出吗?

我在这里检查了其他类似的问题,有些人建议我检查文件系统是否使用nosuid选项挂载,所以我执行mount | /dev/sda1并得到了输出:

/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
Run Code Online (Sandbox Code Playgroud)

这意味着未启用此选项。

关于为什么我没有得到预期输出的任何提示?

小智 6

system(3)库函数将其传递到运行其命令参数/bin/sh -c,而/bin/sh在Linux(或bashdashmksh)放弃任何setuid或setgid特权,除非调用的-p选项。

bash 联机帮助页说:

如果 shell 以不等于真实用户(组)id 的有效用户(组)id 启动,并且未提供-p选项[...] 有效用户 id 设置为真实用户 id。

对于dash/bin/sh来自 Debian/Ubuntu),这是一种新情况:在 Debian 9 Stretch(2017 年)中还不是这种情况,这只是 Debian 特定的更改,截至 2020 年 2 月仍不在上游代码中-04. bash自 2.X 版本(首次包含在 RedHat 7.X 中,2000 年)以来就有此功能。

这是还没有的情况下与其他炮弹(ksh93zsh,等),或者与/bin/sh其他系统(OpenBSD的,FreeBSD的,的Solaris;它被而不是NetBSD的改变工作诸如bash)。

如果他们有它,他们的特权模式下工作不同比在bash:它原来当外壳在setuid的方式运行在默认情况下,你必须把它关闭set +p以有壳下降了setuid权限。


如果您想直接从您的 setuid 二进制文件中使用system()popen()或运行 shell 或可执行的 shell 脚本,那么您应该放弃任何“分裂人格”,并通过以下方式完全切换到您的真实或有效凭据setres[ug]id

% cat a.cc
#include <unistd.h>
#include <stdlib.h>
int main(){
    uid_t euid = geteuid();
    setresuid(euid, euid, euid);
    system("id");
}
% c++ a.cc
% chmod u+s a.out
% ./a.out
uid=1002(fabe)
% su -c ./a.out
uid=1002(fabe)
Run Code Online (Sandbox Code Playgroud)

如果您只想检查您的二进制文件是否真的切换了其有效凭据,请直接执行此操作,而不是通过以下方式调用外部程序system()

#include <iostream>
#include <unistd.h>
#include <pwd.h>
using namespace std;
int main(){
    uid_t euid = geteuid(); struct passwd *pw = getpwuid(euid);
    cout << "euid=" << euid;
    if(pw) cout << ", " << pw->pw_name;
    cout << endl;
}
Run Code Online (Sandbox Code Playgroud)