為什麼 setuid 位工作不一致?
我寫了程式碼:
// a.c #include <stdlib.h> int main () { system("/bin/sh"); return 0; }
用命令編譯:
gcc a.c -o a.out
在其上添加了 setuid 位:
sudo chown root.root a.out sudo chmod 4755 a.out
在 Ubuntu 14.04 上,當我以普通使用者身份執行時,我獲得了 root 權限。
但是在 Ubuntu 16.04 上,我仍然得到了目前使用者的 shell。
為什麼不一樣?
改變的是,
/bin/sh
要麼變成bash
要麼留下dash
,它有一個額外的標誌來-p
模仿 bash 的行為。Bash 要求該
-p
標誌不放棄 setuid 特權,如其手冊頁中所述:如果 shell 以不等於實際使用者(組)id 的有效使用者(組)id 啟動,並且未提供 -p 選項,則不讀取啟動文件,不從環境繼承 shell 函式,SHELLOPTS , BASHOPTS, CDPATH, 和 GLOBIGNORE 變數,如果它們出現在環境中,將被忽略,有效使用者 id 設置為真實使用者 id。如果在呼叫時提供了 -p 選項,則啟動行為是相同的,但不會重置有效使用者 ID。
以前,
dash
不關心這一點並允許執行 setuid(不採取任何措施來阻止它)。但是Ubuntu 16.04 的手冊dash
頁有一個附加選項描述,類似於bash
:-p priv
如果有效的 uid 與 uid 不匹配,則不要嘗試重置它。預設情況下未設置此項,以幫助避免setuid root 程序通過 system(3) 或 popen(3) 錯誤使用。
此選項在上游(可能對提議的更新檔*沒有反應)和 Debian 9 中都不存在,但存在於自 2018 年以來獲得更新檔的 Debian buster 中。
注意:正如 Stéphane Chazelas 所解釋的,現在呼叫為時已晚
"/bin/sh -p"
,system()
因為system()
執行通過/bin/sh
的任何內容,因此 setuid 已經被刪除。derobert的答案在之前的程式碼中解釋瞭如何處理這個問題system()
。