實驗2:SET-UID程序漏洞實驗

SET-UID程序漏洞實驗

1、實驗描述

Set-UID 是Unix系統中的一個重要的安全機制。當一個Set-UID程序運行的時候,它被假設爲具備擁有者的權限。例如,若是程序的擁有者是root,那麼任何人運行這個程序時都會得到程序擁有者的權限。Set-UID容許咱們作許多頗有趣的事情,可是不幸的是,它也是不少壞事情的罪魁禍首。linux

所以本次實驗的目標有兩點:程序員

1.欣賞好的方面,理解爲何Set-UID是須要的,以及它是如何被執行的。shell

2.注意壞的方面,理解它潛在的安全性問題。ubuntu

2、實驗內容

這是一個探索性的實驗,你的任務是在Linux環境中和Set-UID機制」玩遊戲「,你須要在Linux中完成接下來的實驗任務:promise

2.1 猜想爲何「passwd」,「chsh」,「su」,和「sudo」命令須要Set-UID機制,若是它們沒有這些機制的話,會發生什麼,若是你不熟悉這些程序,你能夠通話閱讀使用手冊來熟悉它們,若是你拷貝這些命令到本身的目錄下,這些程序就不會是Set-UID程序,運行這些拷貝的程序,觀察將會發生什麼。

從上面的截圖能夠看出:將passwd拷貝到/tmp/下,權限發生了變化(在原目錄下suid位被設置),復件沒有了修改密碼的權限。安全

對於「chsh」,「su」,和「sudo」命令,把這些程序拷貝到用戶目錄下,一樣再也不具備root權限。bash

2.2 在linux環境下運行Set-UID 程序,同時描述而且解釋你的觀察結果

2.2.1 以root方式登陸,拷貝/bin/zsh 到/tmp, 同時設置拷貝到tmp目錄下的zsh爲set-uid root權限,而後以普通用戶登陸,運行/tmp/zsh。你會獲得root權限嗎?請描述你的結果。

如圖所示,得到了權限函數

2.2.2 拷貝/bin/bash到/tmp目錄,同時設置/tmp目錄下的bash爲Set-UID root權限,而後以普通用戶登陸,運行/tmp/bash。你會獲得root權限嗎?請描述你的結果。

可見,一樣的操做,運行復制的zsh能夠得到root權限,而bash不能。學習

2.3 從上面步驟能夠看出,/bin/bash有某種內在的保護機制能夠阻止Set-UID機制的濫用。爲了可以體驗這種內在的保護機制出現以前的情形,咱們打算使用另一種shell程序——/bin/zsh。在一些linux的發行版中(好比Redora和Ubuntu),/bin/sh其實是/bin/bash的符號連接。爲了使用zsh,咱們須要把/bin/sh連接到/bin/zsh。

下面的指令將會把默認的shell指向zsh:ui

$sudo su Password: #cd /bin #rm sh #ln -s zsh sh 

2.4 PATH環境變量的設置

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; } 
2.4.1 你可以設置這個Set-UID程序運行你本身的代碼而不是/bin/ls嗎?若是你能的話,你的代碼具備root權限嗎?描述並解釋你的觀察。

能夠具備root權限,把/bin/sh拷貝到/tmp目錄下面重命名爲ls(先要確保/bin/目錄下的sh 符號連接到zsh,而不是bash),將環境變量PATH設置爲當前目錄/tmp,運行編譯的程序test。就能夠得到root權限:

2.4.2 修改/bin/sh使得其返回到/bin/bash,重複上面的攻擊,你仍然能夠得到root權限嗎?描述並解釋你的觀察。

可見修改sh鏈接回bash,運行test程序不能使普通用戶得到root權限。

2.5 sytem()和execve()的不一樣

首先確保/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 ; } 
2.5.1 程序中有 q=0。程序會使用system()調用命令行。這個命令安全碼?若是你是Bob,你能對系統的完整性妥協嗎?你能從新移動一個對你沒有寫權限的文件嗎?

這個命令不安全,Bob可能會出於好奇或者我的利益驅使閱讀或者修改只有root用戶才能夠運行的一些文件。好比截圖中:file文件只有root用戶有讀寫權限,但普通用戶經過運行該程序,閱讀並重命名了file文件:

第二次作:

2.5.2 若是令q=1;剛纔的攻擊還會有效嗎?請描述並解釋你的觀察。

修改成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環境變量,解釋緣由。

2.6.1 把myprog編譯成一個普通用戶下的程序在普通用戶下運行

可見,它會使用LD_PRELOAD環境變量,重載sleep函數

2.6.2 把myprog編譯成一個Set-UID root的程序在普通用戶下運行

在這種狀況下,忽略LD_PRELOAD環境變量,不重載sleep函數,使用系統自帶的sleep函數:

 

2.6.3 把myprog編譯成一個Set-UID root的程序在root下運行

在這種狀況下,使用LD_PRELOAD環境變量,使用重載的sleep函數:

2.6.4在一個普通用戶下把myprog編譯成一個Set-UID 普通用戶的程序在另外一個普通用戶下運行

在這種狀況下,不會重載sleep函數:

出現了權限不夠的問題有待解決。

由以上四種狀況可見:只有用戶本身建立的程序本身去運行,纔會使用LD_PRELOAD環境變量,重載sleep函數,不然的話忽略LD_PRELOAD環境變量,不會重載sleep函數。

2.7 消除和清理特權

爲了更加安全,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函數以前,就能避免這個問題。

 

 3、實驗感想

  在自學或者聽老師講課時,只是明白了這一部分知識的理論狀況。作實驗時才能更清楚的理解到這些知識的應用層面。

 不少在學習時不是很明白的知識,概念,或者某個語句的應用,在實驗中能獲得充分的應用。

此次實驗室學習了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這個文件會被修改。

相關文章
相關標籤/搜索