setuid 不起作用

setuid 不起作用

我试图了解如何setuid运作。

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

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


int main(){
    cout << system("id -a") << "\n";
    cout << system("whoami")  << "\n";
}

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

-rwxrwxr-x 1 anmol anmol 9972 Feb  1 16:54 my-binary

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

-rwsrwsr-x 1 anmol anmol 9972 Feb  1 16:54 my-binary

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

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

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

uid=1001(user2) gid=1001(user2) groups=1001(user2)
user2

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

uid=1001(root) gid=1001(root) groups=1001(root)
root

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

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

/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)

这意味着该选项未启用。

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

答案1

system(3)函数通过将其传递给 来运行其命令参数/bin/sh -c/bin/shLinux 上的 ( 、bashdashmksh将放弃任何 setuid 或 setgid 权限,除非使用该-p选项调用。

bash 手册页说:

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

对于dash/bin/sh来自 Debian/Ubuntu),这是有点新:Debian 9 Stretch (2017) 中还没有这种情况,它只是 Debian 特定的改变,仍然不在上游来源截至 2020 年 2 月 4 日。bash从 2.X 版本开始(首次包含在 RedHat 7.X,2000 年)就已经有了这个。

这是情况仍然不是这样与其他 shell(ksh93zsh等)或来自/bin/sh其他系统(OpenBSD、FreeBSD、Solaris;但不是 NetBSD)改变了像 bash 一样工作)。

如果他们拥有它,他们的特权模式就可以工作不同地与 bash 相比:它已经变成了默认情况下,当 shell 以 setuid 模式运行时,您必须将其打开离开withset +p以使 shell 删除 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)

如果您只想检查您的二进制文件是否确实切换了其有效凭据,请直接执行此操作,而不是通过以下方式调用外部程序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;
}

相关内容