suid 執行檔沒有提升權限,但sudo
確實提升了
我正在嘗試編寫一個程序,該程序將在不提示輸入密碼或確認的情況下快速關閉筆記型電腦。筆記型電腦執行的是 Linux,特別是 Manjaro。
為此,我正在嘗試製作一個使用固定參數執行的
setuid
執行檔(並且還生成一個 shell)。我在這裡只是為了保持程序簡短,從安全的角度來看這是一個糟糕的主意。downnow``shutdown``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.
ch{own,grp,mod}
我在ing之前和之後收到相同的消息。
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
可能是因為沒有
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.
設置權限位僅允許您的應用程序使用該
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; }