實驗七-緩衝區溢位(20221414徐鹿鳴)
指導書內容
- 輸入命令安裝一些用於編譯 32 位 C 程式的軟體包:
sudo apt-get update
sudo apt-get install -y lib32z1 libc6-dev-i386 lib32readline6-dev
sudo apt-get install gdb - 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。下面的指令描述瞭如何設定 zsh 程式:
sudo su
cd /bin
rm sh
ln -s zsh sh
exit - 輸入命令 linux32 進入32位linux環境。此時你會發現,命令列用起來沒那麼爽了,比如不能tab補全了,輸入 /bin/bash 使用bash
- 在 /tmp 目錄下新建一個 stack.c 檔案:
cd /tmp
vim stack.c - 按 i 鍵切換到插入模式,再輸入如下內容。通過程式碼可以知道,程式會讀取一個名為“badfile”的檔案,並將檔案內容裝入“buffer”。
(複製程式碼如果出現縮排混亂可先在 Vim 執行 :set paste 再按 i 鍵編輯。)
int bof(char *str) { char buffer[12]; /* The following statement has a buffer overflow problem */ 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; }
- 編譯該程式,並設定 SET-UID。命令如下:
sudo su
gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c
chmod u+s stack
exit
(GCC編譯器有一種棧保護機制來阻止緩衝區溢位,所以我們在編譯程式碼時需要用 –fno-stack-protector 關閉這種機制。 而 -z execstack 用於允許執行棧。
(-g 引數是為了使編譯後得到的可執行文件能用 gdb 除錯。)
-
直接下載程式碼:wget http://labfile.oss.aliyuncs.com/courses/231/exploit.c
-
現在我們要得到 shellcode 在記憶體中的地址,輸入命令進入 gdb 除錯:
gdb stack
disass main -
esp 中就是 str 的起始地址,所以我們在地址 0x080484ee 處設定斷點。地址可能不一致,請根據你的顯示結果自行修改。
# 設定斷點
b *0x080484ee
r
i r $esp -
最後獲得的這個 0xffffcfb0 就是 str 的地址。
按 q 鍵,再按 y 鍵可退出除錯。
根據語句 strcpy(buffer + 100,shellcode); 我們計算 shellcode 的地址為 0xffffcfb0 + 0x64 = 0xffffd014
現在修改 exploit.c 檔案,將 \x??\x??\x??\x?? 修改為計算的結果 \x14\xd0\xff\xff,注意順序是反的。 -
然後,編譯 exploit.c 程式:gcc -m32 -o exploit exploit.c
先執行攻擊程式 exploit,再執行漏洞程式 stack,觀察結果:
我的實驗結果如下:
緩衝區溢位的原理:
緩衝區溢位是指程式試圖向緩衝區寫入超出預分配固定長度資料的情況。這一漏洞可以被惡意使用者利用來改變程式的流控制,甚至執行程式碼的任意片段。這一漏洞的出現是由於資料緩衝器和返回地址的暫時關閉,溢位會引起返回地址被重寫。
緩衝區溢位的保護方法:
目前有四種基本的方法保護緩衝區免受緩衝區溢位的攻擊和影響:
1.強制寫正確的程式碼的方法
編寫正確的程式碼是一件非常有意義但耗時的工作,特別像編寫C語言那種具有容易出錯傾向的程式(如:字串的零結尾),這種風格是由於追求效能而忽視正確性的傳統引起的。儘管花了很長的時間使得人們知道了如何編寫安全的程式,具有安全漏洞的程式依舊出現。因此人們開發了一些工具和技術來幫助經驗不足的程式設計師編寫安全正確的程式。雖然這些工具幫助程式設計師開發更安全的程式,但是由於C語言的特點,這些工具不可能找出所有的緩衝區溢位漏洞。所以,偵錯技術只能用來減少緩衝區溢位的可能,並不能完全地消除它的存在。除非程式設計師能保證他的程式萬無一失,否則還是要用到以下部分的內容來保證程式的可靠效能。
2.通過作業系統使得緩衝區不可執行,從而阻止攻擊者殖入攻擊程式碼
這種方法有效地阻止了很多緩衝區溢位的攻擊,但是攻擊者並不一定要殖入攻擊程式碼來實現緩衝區溢位的攻擊,所以這種方法還是存在很多弱點的。
3.利用編譯器的邊界檢查來實現緩衝區的保護
這個方法使得緩衝區溢位不可能出現,從而完全消除了緩衝區溢位的威脅,但是相對而言代價比較大。
4.在程式指標失效前進行完整性檢查
這樣雖然這種方法不能使得所有的緩衝區溢位失效,但它的確確阻止了絕大多數的緩衝區溢位攻擊,而能夠逃脫這種方法保護的緩衝區溢位也很難實現。