Set-UID 是Unix系統中的一個重要的安全機制。當一個Set-UID程序運行的時候,它被假設爲具備擁有者的權限。例如,若是程序的擁有者是root,那麼任何人運行這個程序時都會得到程序擁有者的權限。Set-UID容許咱們作許多頗有趣的事情,可是不幸的是,它也是不少壞事情的罪魁禍首。linux
所以本次實驗的目標有兩點:程序員
1.欣賞好的方面,理解爲何Set-UID是須要的,以及它是如何被執行的。shell
2.注意壞的方面,理解它潛在的安全性問題。ubuntu
這是一個探索性的實驗,你的任務是在Linux環境中和Set-UID機制」玩遊戲「,你須要在Linux中完成接下來的實驗任務:promise
從上面的截圖能夠看出:將passwd拷貝到/tmp/下,權限發生了變化(在原目錄下suid位被設置),復件沒有了修改密碼的權限。安全
對於「chsh」,「su」,和「sudo」命令,把這些程序拷貝到用戶目錄下,一樣再也不具備root權限。bash
如圖所示,得到了權限函數
可見,一樣的操做,運行復制的zsh能夠得到root權限,而bash不能。學習
下面的指令將會把默認的shell指向zsh:ui
$sudo su Password: #cd /bin #rm sh #ln -s zsh sh
system(const char * cmd)系統調用函數被內嵌到一個程序中執行一個命令,system()調用/bin/sh來執行shell程序,而後shell程序去執行cmd命令。可是在一個Set-UID程序中system()函數調用shell是很是危險的,這是由於shell程序的行爲能夠被環境變量影響,好比PATH;而這些環境變量能夠在用戶的控制當中。經過控制這些變量,用心險惡的用戶就能夠控制Set-UID程序的行爲。
下面的Set-UID程序被用來執行/bin/ls命令;而後程序員能夠爲ls命令使用相對路徑,而不是絕對路徑。
int main() { system("ls"); return 0; }
能夠具備root權限,把/bin/sh拷貝到/tmp目錄下面重命名爲ls(先要確保/bin/目錄下的sh 符號連接到zsh,而不是bash),將環境變量PATH設置爲當前目錄/tmp,運行編譯的程序test。就能夠得到root權限:
可見修改sh鏈接回bash,運行test程序不能使普通用戶得到root權限。
首先確保/bin/sh指向zsh
背景:Bob在爲一家審計代理處工做,他正在調查一家公司是否存在詐騙行爲。爲了這個目的,他須要閱讀這家公司在Unix系統中的全部文件;另外一方面,爲了保護系統的可靠性,他不能修改任何一個文件。爲了達到這個目的,Vince——系統的超級用戶爲他寫了一個SET-ROOT-UID程序,而且給了Bob能夠執行它的權限。這個程序須要Bob在命令行中打出一個文件名,而後運行/bin/cat命令顯示這個文件。既然這個程序是以root權限運行的,它就能夠顯示Bob想看的任何一個文件。然而,既然這個程序沒有寫操做,Vince很確信Bob不能用這個程序修改任何文件。
#include <string.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { char *v[3]; if(argc < 2) { printf("Please type a file name.\n"); return 1; } v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = 0; //Set q = 0 for Question a, and q = 1 for Question b int q = 0; if (q == 0) { char *command = malloc(strlen(v[0]) + strlen(v[1]) + 2); sprintf(command, "%s %s", v[0], v[1]); system(command); } else execve(v[0], v, 0); return 0 ; }
這個命令不安全,Bob可能會出於好奇或者我的利益驅使閱讀或者修改只有root用戶才能夠運行的一些文件。好比截圖中:file文件只有root用戶有讀寫權限,但普通用戶經過運行該程序,閱讀並重命名了file文件:
第二次作:
修改成q=1後,不會有效。前面步驟之因此有效,是由於system()函數調用/bin/sh,連接至zsh,具備root權限執行了cat file文件後,接着執行mv file file_new命令。
而當令q=1, execve()函數會把file; mv file file_new 當作是一個文件名,系統會提示不存在這個文件:
如圖所示文件被修改了,緣由在於設置uid前,zzz文件就已經被打開了。只要將語句setuid(getuid())移至調用open函數以前,就能避免這個問題。
2.6 LD_PRELOAD環境變量
爲了保證Set-UID程序在LD_PRELOAD環境的操縱下是安全的,動態連接器會忽略環境變量,可是在某些條件下是例外的,在下面的任務中,咱們猜想這些特殊的條件究竟是什麼。
一、讓咱們創建一個動態連接庫。把下面的程序命名爲mylib.c,放在/tmp目錄下。在函數庫libc中重載了sleep函數:
#include <stdio.h>
void sleep (int s)
{
printf("I am not sleeping!\n");
}
二、咱們用下面的命令編譯上面的程序(注意區別l和1):
gcc -fPIC -g -c mylib.c
gcc -shared -Wl,-soname,libmylib.so.1 \
-o libmylib.so.1.0.1 mylib.o –lc
三、把下面的程序命名爲myprog.c,放在/tmp目錄下:
int main()
{
sleep(1);
return 0;
}
請在下面的條件下運行這些程序,並觀察結果。基於這些觀察告訴咱們連接器何時會忽略LD_PRELOAD環境變量,解釋緣由。
可見,它會使用LD_PRELOAD環境變量,重載sleep函數
在這種狀況下,忽略LD_PRELOAD環境變量,不重載sleep函數,使用系統自帶的sleep函數:
在這種狀況下,使用LD_PRELOAD環境變量,使用重載的sleep函數:
在這種狀況下,不會重載sleep函數:
出現了權限不夠的問題有待解決。
由以上四種狀況可見:只有用戶本身建立的程序本身去運行,纔會使用LD_PRELOAD環境變量,重載sleep函數,不然的話忽略LD_PRELOAD環境變量,不會重載sleep函數。
爲了更加安全,Set-UID程序一般會調用setuid()系統調用函數永久的清除它們的root權限。然而有些時候,這樣作是遠遠不夠的。在root用戶下,在/tmp目錄新建一個空文件zzz。在root用戶下將下面代碼命名爲test.c,放在/tmp目錄下,編譯這個程序,給這個程序設置root權限。在一個普通的用戶下,運行這個程序。描述你所觀察到的狀況,/tmp/zzz這個文件會被修改嗎?解釋你的觀察。
代碼:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{
int fd;
//Assume that /tmp/zzz is an important system file,
//and it is owned by root with permission 0644
fd = open("/tmp/zzz", O_RDWR | O_APPEND);
// Simulate the tasks conducted by the program
sleep(1);
// After the task, the root privileges are no longer needed,
//it’s time to relinquish the root privileges permanently.
setuid(getuid()); // getuid() returns the real uid
if (fork())
{ // In the parent process
close (fd);
exit(0);
}
else
{ // in the child process
//Now, assume that the child process is compromised, malicious
//attackers have injected the following statements
//into this process
write (fd, "shiyanlou!", 10);
close (fd);
}
}
如圖所示文件被修改了,緣由在於設置uid前,zzz文件就已經被打開了。只要將語句setuid(getuid())移至調用open函數以前,就能避免這個問題。
在自學或者聽老師講課時,只是明白了這一部分知識的理論狀況。作實驗時才能更清楚的理解到這些知識的應用層面。
不少在學習時不是很明白的知識,概念,或者某個語句的應用,在實驗中能獲得充分的應用。
此次實驗室學習了Set-UID的應用,利用他賦予用戶root權限,其中仍然有一些語句不是很明白,還須要多加學習。
1.將含有set-uid機制的文件移入本身文件夾內,將不能運行其正常功能。但若在root權限下移入,將能夠獲得root權限,運行這個文件;
2.bash有一種保護機制,使得其在root下移入別的文件夾也不能得到root權限;
3..chmod u+s zsh 設置zsh爲set-uid root權限;
4./bin/目錄下的sh 符號連接到zsh,將環境變量PATH設置爲當前目錄/tmp,運行編譯的程序test,就能夠得到root權限,若修改sh鏈接回bash,運行test程序不能使普通用戶得到root權限;
四、只有用戶本身建立的程序本身去運行,纔會使用LD_PRELOAD環境變量,重載sleep函數,不然的話忽略LD_PRELOAD環境變量,不會重載sleep函數;
五、將語句setuid(getuid())移至調用open函數以前,能在一個普通的用戶下,防止tmp/zzz這個文件會被修改。