为什么 setuid() 不适用于非 root 用户?

为什么 setuid() 不适用于非 root 用户?

setuid()我遇到了关于setuid 位的奇怪行为。

看起来 suid 位和 setuid() 没有按预期工作。我期待一个带有 +s 且由 uid 1001 拥有的二进制文件,该二进制文件setuid(1001)可以从任何 uid 调用,并在调用后假定 uid 1001。然而,这似乎只有在以下情况下才有效:

  1. +s 未设置且调用用户为 root
  2. +s 已设置,并且二进制文件属于 root

我希望我忽略了一个细节,但我找不到我的错误。

最终目标是拥有一个可以从任何用户调用并假定固定 uid 的二进制文件。我不希望它由 root 拥有,而是由应该假定其身份的用户拥有(主要是因为这是堆栈粉碎的练习,并且允许 priv esc)。

我创建了一个最小的示例来确定我的问题,如下所示:

考虑测试.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main() {
        int t = setuid(1001);
        if (t < 0) {
                perror("Error with setuid() - errno " + errno);
        }
        else {
                printf("did work fine, look who I am:.\n");
                system("/bin/bash -c whoami");
        }
}

另外,passwd 在相关部分看起来像这样:

test1:x:1000:1000::/home/test1:/bin/sh
test2:x:1001:1001::/home/test2:/bin/sh

现在,考虑这个输出:

root@kali:/tmp/test# ls -la
total 12
drwxr-xr-x  2 root root 4096 Oct 24 09:53 .
drwxrwxrwt 18 root root 4096 Oct 24 09:52 ..
-rw-r--r--  1 root root  304 Oct 24 09:51 test.c
root@kali:/tmp/test# gcc test.c -o test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chown test2:test2 test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
root
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test1
$ 

如您所见,没有显示错误,但未正确假定所需的 uid。雪上加霜的是,请考虑一下:

root@kali:/tmp/test# chown root:root test
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test2

所以我想我的问题是:我做错了什么?为什么setreuid()有效和setuid()无效?

我尝试过的其他事情:使用execve(),在 ubuntu 18.04 下复制,使用 /bin/sh 而不是 /bin/bash。

答案1

的定义setuid()有点奇怪,因为它根据应用程序是否为 setuid root 执行不同的操作。 (有充分的理由,但乍一看不一定是明显的原因。)

从根本上讲,您需要的是在调用之前放弃原始用户标识system(),因为某些 shell 会尽力拒绝遵守 setuid。这是您的代码的修改版本;使用和不使用注释行运行它以查看差异。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int t;

    printf("before, geteuid() returned %d\n", geteuid());
    printf("before, getuid() returned %d\n", getuid());

    t = setuid(geteuid());
    if (t < 0) {
        perror("Error with setuid() - errno " + errno);
        exit(1);
    }

    printf("after, geteuid() returned %d\n", geteuid());
    printf("after, getuid() returned %d\n", getuid());

    // setreuid(geteuid(), geteuid());

    printf("finally, geteuid() returned %d\n", geteuid());
    printf("finally, getuid() returned %d\n", getuid());

    printf("did work fine, look who I am:\n");
    system("/bin/bash -c whoami");
}

相关内容