Linux
為什麼 setuid() 不適用於非 root 使用者?
我遇到了關於
setuid()
setuid 位的奇怪行為。suid 位和 setuid() 似乎沒有按預期工作。我期待一個帶有 +s 並由 uid 1001 擁有的二進製文件,該二進製文件
setuid(1001)
從任何 uid 呼叫,並在呼叫後假定 uid 1001。然而,這似乎只有在以下任一情況下才有效:
- +s 未設置且呼叫使用者為 root
- +s 已設置並且二進製文件屬於 root
我期待我忽略了一個細節,但是我找不到我的錯誤。
最終目標是擁有一個可以從任何使用者呼叫的二進製文件並假設一個固定的 uid。我不希望它由 root 擁有,而是由應該假定其身份的使用者擁有(主要是因為這是一個關於堆棧粉碎的練習,並且允許 priv esc)。
我創建了一個最小的範例來確定我的問題,這裡是:
考慮 test.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。
for 的定義
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"); }