Linux

為什麼 setuid 位工作不一致?

  • May 17, 2019

我寫了程式碼:

// 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()

*這里那裡的更多歷史細節。

引用自:https://unix.stackexchange.com/questions/519338