suid 可执行文件未提升权限,但“sudo”确实提升了权限

suid 可执行文件未提升权限,但“sudo”确实提升了权限

我正在尝试编写一个程序,可以快速关闭笔记本电脑,而不提示输入密码或确认。该笔记本电脑运行的是 Linux,特别是 Manjaro。

为此,我试图创建一个setuid名为 的可执行文件downnow,它使用固定参数执行shutdown(并且还生成一个 shell)。我在这里使用只是system为了保持程序简短,从安全角度来看这是一个糟糕的主意。

// downnow.c
#include <stdlib.h>

int main() {
  system("shutdown --no-wall --halt now");
  return 0;
}

然后我编译downnow,将其移动到/bin,更改其所有者并授予它 setuid 和 setgid 权限:

$ sudo chown root /bin/downnow 

$ sudo chgrp root /bin/downnow 

$ sudo chmod u+s /bin/downnow 

$ sudo chmod g+s /bin/downnow 

但是,当我尝试以非特权用户身份执行时downnow,它无法与 systemd 通信。

$ downnow 
Failed to halt system via logind: Interactive authentication required.
Failed to talk to init daemon.

我在 ing 之前和之后收到相同的消息ch{own,grp,mod}

stat/bin/downnow报告和上具有相同的权限/usr/bin/sudo

$ stat /bin/downnow 
  File: /bin/downnow
  Size: XXXX        Blocks: XX         IO Block: XXXX   regular file
Device: XXXXX/XXXXX Inode: XXXXXX     Links: 1
Access: (6755/-rwsr-sr-x)  Uid: (    0/    root)   Gid: (    0/    root)

$ stat /usr/bin/sudo
  File: /usr/bin/sudo
  Size: XXXXXX      Blocks: XXX        IO Block: XXXX   regular file
Device: XXXXX/XXXXX Inode: XXXXXXX     Links: 1
Access: (4755/-rwsr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)

为什么在完美运行的情况下可能downnow无法提升其权限?sudo

答案1

设置权限位仅允许您的应用程序使用该setuid调用,而其本身不会更改您的权限。为此,您需要使用 来设置 uid setuid(uid_t uid)。有关详细信息,请参阅手册页:https://linux.die.net/man/2/setuid

可以用来geteuid()获取当前有效的uid(即具有setuid权限的文件的所有者)。请参阅手册页:https://linux.die.net/man/2/geteuid

例子:

// downnow.c
#include <stdlib.h>
#include <unistd.h>

int main() {
  setuid(geteuid());
  system("shutdown --no-wall --halt now");
  return 0;
}

答案2

可能是因为没有接到setuid(2)电话。以下是此类调用的前后对比:

#include <err.h>
#include <stdio.h>
#include <unistd.h>

#define GETUIDS(p) (p[0]=getuid(),p[1]=geteuid())

int main(void)
{
    uid_t ids[2];
    GETUIDS(ids);
    fprintf(stderr, "real %lu effective %lu\n", (unsigned long) ids[0],
            (unsigned long) ids[1]);
    if (setuid(0) == -1)
        err(1, "setuid failed");
    GETUIDS(ids);
    fprintf(stderr, "real %lu effective %lu\n", (unsigned long) ids[0],
            (unsigned long) ids[1]);
    return 0;
}

而且你的包装纸也不是很安全;希望它不会逃逸到多用户系统。避免不必要的 shell 调用可能会更安全(除非您喜欢 shellshock 类型的漏洞或对重复环境变量的奇怪处理,例如bash……),而使用exec(3)调用来shutdown直接替换您的进程:

#include <err.h>
#include <unistd.h>

int main()
{
    if (setuid(0) == -1)
        err(1, "setuid failed");
    //execl("/usr/bin/echo", "echo", "--no-wall", "--halt", "now",
    execl("/usr/sbin/shutdown", "shutdown", "--no-wall", "--halt", "now",
          (char *) 0);
    err(1, "exec failed");
    return 1;
}

后来有几次意外关机...

centos7# make badcode
cc     badcode.c   -o badcode
centos7# mv badcode /badcode
centos7# chmod u+s /badcode
centos7# su - jhqdoe
Last login: Thu Jan 10 01:39:03 UTC 2019 on pts/0
[jhqdoe@centos7 ~]$ /badcode
Connection to 192.168.99.2 closed by remote host.
Connection to 192.168.99.2 closed.

相关内容