setuid()與setgid() -- 設定 UID 和 GID

2puT發表於2016-07-21
用 setuid() 設定實際使用者 UID 和有效使用者 UID。
用 setgid() 設定實際組 ID 和有效組 ID。
兩個函式宣告如下
setuid()與setgid() <wbr>-- <wbr>設定 <wbr>UID <wbr>和 <wbr>GID
在使用該函式時會遇到以下情況:
1. 若程式有 root 許可權,則函式將實際使用者 ID、有效使用者 ID 設定為引數 uid 。使用 root執行下面程式碼:
setuid()與setgid() <wbr>-- <wbr>設定 <wbr>UID <wbr>和 <wbr>GID
執行輸出:
引用
# ./setuid.exe 1001
real uid: 0
effective uid: 0
real uid: 1001
effective uid: 1001

由此可見,在 root 下,實際使用者 ID 和有效使用者 ID 均被設為 setuid() 的引數 uid 的值。

2. 若程式不具有 root 許可權,那麼普通使用者使用 setuid() 時引數 uid只能是自己的,沒有許可權設定別的數值,否則返回失敗:
引用
$ ./setuid.exe 1001
real uid: 1000
effective uid: 1000
setuid error: Operation not permitted
real uid: 1000
effective uid: 1000


由以上可以看出,只有超級使用者程式才能更改實際使用者 ID 。所以一個非特權使用者程式不能通過 setuid 或 seteuid得到特權使用者許可權。但是 su 命令卻能使一個普通使用者變成特權使用者。這並不矛盾,因為 su 是一個 "set_uid"程式。執行一個設定了 "set_uid" 位的程式時,核心將程式的有效使用者 ID 設定為檔案屬主的 ID(root 的ID)。而核心檢查一個程式是否具有訪問某許可權時,是使用程式的有效使用者 ID 來進行檢查的。su 程式的檔案屬主是root,普通使用者執行 su 命令時,su 程式的許可權是 root 許可權。 

Warning:對於呼叫了 setuid() 函式的程式要格外小心,當程式的有效使用者 ID 即 euid 是root 使用者時,如果呼叫 setuid() 使 euid 為其他非 root使用者,則該程式從此就不具有超級使用者許可權了。看下面程式碼:
setuid()與setgid() <wbr>-- <wbr>設定 <wbr>UID <wbr>和 <wbr>GID
我們使用 root 編譯上面的程式,並執行 chmod u+s 給程式新增 suid 位,然後以普通使用者來執行它。
在上面程式中,在執行 setuid (1000) 函式時,我們還是具有 root 許可權的,所以該函式會設定成功。正是因為有了 root許可權,所以 3 個 ID (真實使用者ID,已儲存使用者ID,有效使用者ID)都會被設定為1000。所以此後程式已經被降權為普通使用者,想再  seteuid(0) 已經不可能。

可以這樣使用 stuid() 函式
開始時,某個程式需要 root 許可權玩成一些工作,但後續的工作不需要 root 許可權。可以將該可執行程式檔案設定 set_uid位,並使得該檔案的屬主為 root。這樣,普通使用者執行這個程式時,程式就具有了 root 許可權,當不再需要 root 許可權時,呼叫setuid( getuid() ) 恢復程式的實際使用者 ID 和有效使用者 ID 為執行該程式的普通使用者的 ID。對於一些提供網路服務的程式,這樣做是非常有必要的,否則就可能被攻擊者利用,使攻擊者控制整個系統。

對於設定了 set_uid 位的可執行程式也要注意,尤其是對那些屬主是 root 的更要注意。因為 Linux 系統中 root使用者擁有最高權力。黑客們往往喜歡尋找設定了 set_uid位的可執行程式的漏洞。這樣的程式如果存在緩衝區溢位漏洞,並且該程式是一個網路程式,那麼黑客就可以從遠端的地方輕鬆地利用該漏洞獲得執行該漏洞程式的主機的root 許可權。即使這樣的成不是網路程式,那麼也可以使本機上的惡意普通使用者提升為 root 許可權。

相關文章