setuid 不工作
我試圖了解如何
setuid
工作。所以我做了一個虛擬程序,它只列印目前使用者:
#include<bits/stdc++.h> using namespace std; int main(){ cout << system("id -a") << "\n"; cout << system("whoami") << "\n"; }
my-binary
我在使用者下編譯並創建了執行檔anmol
:-rwxrwxr-x 1 anmol anmol 9972 Feb 1 16:54 my-binary
然後,我
setuid
使用以下方式設置選項chmod +s
:-rwsrwsr-x 1 anmol anmol 9972 Feb 1 16:54 my-binary
如果我正常執行它,我會得到以下輸出:
uid=1000(anmol) gid=1000(anmol) groups=1000(anmol),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),122(sambashare) anmol
現在,如果我使用 更改為另一個使用者
su user2
,然後執行它,我會得到:uid=1001(user2) gid=1001(user2) groups=1001(user2) user2
當我使用 執行它時
sudo ./my-binary
,我得到:uid=1001(root) gid=1001(root) groups=1001(root) root
據我了解,無論我如何執行它,我不應該每次都得到第一個輸出嗎?
我在這裡檢查了其他類似的問題,有些人建議我檢查文件系統是否使用
nosuid
選項掛載,所以我執行mount | /dev/sda1
並得到了輸出:/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
這意味著此選項未啟用。
關於為什麼我沒有得到預期輸出的任何提示?
庫
system(3)
函式通過將其傳遞給 來執行它的命令參數/bin/sh -c
,並且/bin/sh
Linux 上的 (或者或bash
)放棄任何 setuid 或 setgid 權限,除非使用該選項呼叫。dash``mksh``-p
bash 手冊頁說:
如果 shell 以不等於真實使用者(組) id 的有效使用者(組) id 啟動,並且未提供
-p
該選項$$ … $$有效使用者 id 設置為真實使用者 id。
使用
dash
(/bin/sh
來自 Debian/Ubuntu),這是一種新的:在 Debian 9 Stretch (2017) 中還沒有這種情況,這只是 Debian 特定的變化,截至 2020 年 2 月仍然沒有在上游源中-04。bash
自從它的 2.X 版本(第一次包含在 RedHat 7.X,2000 中)以來就已經有了這個。對於其他 shell(,等)或其他系統(OpenBSD、FreeBSD、Solaris;但不是 NetBSD,它被更改為像 bash 一樣工作)仍然不是這種情況。
ksh93``zsh``/bin/sh
如果他們有它,他們的特權模式的工作方式與 bash不同:當 shell 在 setuid 模式下執行時,它預設打開,你必須關閉它才能
set +p
讓 shell 刪除 setuid 權限。如果您想直接從您的 setuid 二進製文件中使用
system()
、popen()
或執行 shell 或可執行 shell 腳本,那麼您應該放棄任何“分裂個性”並通過以下方式完全切換到您的真實或有效憑據setres[ug]id
:% cat a.cc #include <unistd.h> #include <stdlib.h> int main(){ uid_t euid = geteuid(); setresuid(euid, euid, euid); system("id"); } % c++ a.cc % chmod u+s a.out % ./a.out uid=1002(fabe) % su -c ./a.out uid=1002(fabe)
如果您只想檢查您的二進製文件是否真的切換了其有效憑據,請直接進行,而不是通過以下方式呼叫外部程序
system()
:#include <iostream> #include <unistd.h> #include <pwd.h> using namespace std; int main(){ uid_t euid = geteuid(); struct passwd *pw = getpwuid(euid); cout << "euid=" << euid; if(pw) cout << ", " << pw->pw_name; cout << endl; }