一、 SUID/SGID概述 有時,沒有被授權的用戶需要完成某項任務。一個例子是passwd程序,它允許用戶改變口令,這就要求改變/etc/passwd文件的口令域。然而系統管理員決不允許普通用戶擁有直接改變這個文件的權利,因為這絕對不是一個好主意。 為了解決這個問題,SUID/SGID便應運而生。UNIX允許程序被授權,當程序被執行的時候,擁有超級用戶的權限,完成時又回到普通用戶的權限。這個主意很好,所以AT&T對它申請了專利。
二、 UNIX下的一些名詞簡介 1.文件權限。確定用戶讀取、修改或執行文件的權力。 r -- 讀訪問 w -- 寫訪問 x -- 執行許可 s -- SUID/SGID t -- sticky位 2.進程。進程是程序運行一次的過程,以完成預定的任務,它不同於程序。每個進程都有一個唯一的進程ID。此外,每個進程還有一些其他標識符:實際用戶ID、實際組ID、有效用戶ID、有效組ID。超級用戶進程的實際用戶ID和有效用戶ID為0。 3.超級用戶root。超級用戶擁有系統的完全控制權。
三、 SUID/SGID的思路 SUID的程序在運行時,將有效用戶ID改變為該程序的所有者ID,使得進程在很大程度上擁有了該程序的所有者的特權。如果被設置為SUID root,那麼這個進程將擁有超級用戶的特權(當然,一些較新版本的UNIX系統加強了這一方面的安全檢測,一定程度上降低了安全隱患)。當進程結束時,又恢復為原來的狀態。 執行時的Real Uid可以通過函數setuid()改變
四、一個SUID程序 下面的程序是用來演示UNIX文件的SUID,取名為parent.c #include 〈stdio.h〉 #include 〈stdlib.h〉 #include 〈unistd.h〉 #include 〈sys/types.h〉 int main(int argc,char **argv) { int i; char **argu; uid_t uid; uid=geteuid(); //獲取調用進程的有效用戶ID if(argc<2){ fprintf(stderr,"usage: %s \n",argv[0]); exit(0); } if(setuid(uid)<0){ fputs("setuid error.\n",stderr); exit(1); } //將調用進程的實際用戶ID設置為有效用戶ID if((argu=(char**)malloc(argc*sizeof(char*)))==NULL){ fputs("malloc error.\n",stderr); exit(1); } //為execvp的參數指針數組分配內存空間 for(i=0;i argu[argc-1]=(char *)0; //參數指針數組以空指針結尾 if(execvp(argv[1],argu)<0){ fputs("exec error.\n",stderr); exit(1); } //用execvp調用命令行參數指定的程序 exit(0); } 該程序將一個SUID的進程轉變為一個超級用戶進程。將此程序編譯成可執行目標文件parent ,用另一個簡單的程序進行檢驗 int main(void){ printf("real uid=%d, effective uid=%d\n",getuid(),geteuid()); exit(0); } 編譯為printuids。運行程序得到下列結果: $ ./parent printuids //正常執行,無特權 real uid=506, effective uid=506 $ su root PassWord: # chown root parent //更改所有者 # chmod u+s parent //添加SUID # exit $ ./parent printuidsv real uid=0, effective uid=0 //該進程轉變為超級用戶進程 某一進程一旦轉變為超級用戶進程,將擁有系統的完全控制權。比如,我們可以這樣執行演示程序: $ ./parent useradd hacker $ ./parent passwd hacker 故而,SUID的程序往往伴隨著一定的安全問題。在早期的UNIX環境中,SUID/SGID的程序調用system()函數就存在著安全性漏洞。
五、 再談SUID/SGID程序的安全問題 有時,一個SUID程序與一個系統程序(或庫函數)之間的交互作用會產生連程序的編制者也不知道的安全漏洞。一個典型的例子是/usr/lib/preserve程序。它被vi和ex編輯器使用,當用戶在寫出對文件的改變前被意外與系統中斷時,它可以自動制作一個正被編輯的文件的拷貝。這個保存的(preserve)程序將改變寫到在一個專門的目錄內的一個臨時文件上,然後利用/bin/mail程序發送給用戶一個"文件已經被存"的通知。 由於人們可能正在編輯一個私人的或一個機密的文件,被preserve程序(舊版)使用的那個目錄不能被一般用戶訪問。為了使preserve程序可以寫入那個目錄,以及使recover程序可以從那裡讀,這些程序被設置為SUID root。 這個preserve程序有三個特點值得注意: 1. 這個程序被設置為SUID root。 2. 該程序以root用戶的身份運行/bin/mail程序。 3. 該程序調用system()函數調用mail程序。 由於system()函數調用shell對命令字符串進行語法分析,而shell則使用IFS變量作為其輸入字段的分割符。早期的shell版本在被調用是時不將此變量恢復為普通字符集。如果先將IFS設置為"/",然後調用vi程序,繼而調用preserve程序,就有可能使usr/lib/preserve程序執行一個在當前目錄下的bin程序(/bin/mail被解析為帶有參數mail的bin程序)。 如果我們利用前面的演示程序編寫一個簡單的shell script文件命名為bin,它就有可能通過上面的安全漏洞被執行: # shell script to make an SUID-root shell # chown root parent chmod 4755 parent 那麼它的後果將是……