setuid()
我遇到了关于setuid 位的奇怪行为。
看起来 suid 位和 setuid() 没有按预期工作。我期待一个带有 +s 且由 uid 1001 拥有的二进制文件,该二进制文件setuid(1001)
可以从任何 uid 调用,并在调用后假定 uid 1001。然而,这似乎只有在以下情况下才有效:
- +s 未设置且调用用户为 root
- +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");
}