簡單實現棧溢位實驗(IDA)

2020-10-11 21:00:01

有關棧溢位的相關知識

最近學校講到了棧溢位,並有一道很基礎的題,在此可以記錄一下,感興趣的人可以瞭解瞭解.
/
棧溢位:
/
首先談到棧溢位,要先說windows系統典型漏洞分析。
/
棧溢位也是其中的一種。
/
要了解棧溢位,要先了解:

1.主角:棧 與 棧幀

棧(音:zhan四聲)是一種特殊的線性計算機內部儲存結構,服從先進後出的一種特殊線性結構,如同彈夾裡的子彈,先放入的子彈,在最下面。棧的結構使其只能在棧的頂端進行增加資料和刪除資料的操作,壓入資料稱為(push),彈出資料稱為(pop).
/

2.記憶體結構

在win32環境下,由高階語言生成的可執行檔案,即PE檔案,(Portable Executable)檔案。在執行可執行檔案時,系統會將其載入到記憶體,並對映出4GB的虛擬儲存空間,然後繼續執行,形成所謂的程序空間。(教材原話)
/
在win32中將程序使用的記憶體按功能可以分為4個區域,如下圖:
/

名稱作用
棧區(stack)用於動態儲存函數之間的呼叫關係低地址
堆區該記憶體區域由程序利用相關函數和運運算元動態申請
程式碼區存放程式組合之後的機械程式碼和唯讀程式,計算機執行程式,會在該區域讀取命令並執行。
資料區用於儲存全域性變數和靜態變數高地址

/
其在計算機記憶體中的結構也如下圖:

棧區↑棧增長方向
堆區↓堆增長方向
程式碼區
資料區

程式碼實現

/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void attack()
{
	printf("TRY IT!.\n");       //attack函數
}
void func()                     //func函數
{
	char password[6] = "ABCDEF";
	char str[6];
	FILE *fp;
	if(!(fp=fopen("D:\\password.txt","r"))) //開啟D槽的password.txt檔案
		exit(0);
	fscanf(fp,"%s",str);           //將str的內容寫入fp
	str[5]='\0';
	if(strcmp(str,password)==0)    //判斷str是否與password相同
		printf("OK.\n");
	else
		printf("NO.\n");            
}
int main()
{
	func();          //執行func函數
	return 0;
}

/

用軟體IDA實現棧溢位實驗(步驟)

/在這裡入圖片描述
在D槽的password.txt中輸入一定量的字串,執行程式,AAAAA…與指定的password並不相同,所以返回了「NO」。

現在開啟IDA.

1.開啟

可以將exe檔案拖入其中
得到如下:
/在這裡插入圖片描述
/
現在展示的IDA適用靜態偵錯,左邊可以清晰地看到函數體,這是IDA比較清晰簡便的一個優點。

2.尋找函數名稱

在這裡插入圖片描述
點選左側的函數名可以進入。右側也可以檢視十六進位制檢視:在這裡插入圖片描述
IDA快捷鍵,按F5可以檢視虛擬碼。虛擬碼可以讓人較為清晰地瞭解函數的部分構造,但不是能執行的程式碼。在這裡,用滑鼠左鍵雙擊左側函數名稱中的func(),再按F5可以進入func函數檢視虛擬碼:

3. F5檢視虛擬碼

在這裡插入圖片描述

在這裡插入圖片描述
在上圖中點選各個變數,可以檢視棧。

4.檢視棧

在這裡插入圖片描述

檢視到str,password,fp在棧中的位置

/

注意到最下面有一個"r"

/

這裡"r"指的是return adress,這裡簡述為ret,ret指的是返回地址,ret在組合中也有涉及。
這裡的ret主要功能是返回下一個函數的地址,用於在一個函數執行完後跳轉到下一個函數,棧溢位攻擊在這裡執行的原理是,通過文字中讀入過量的資料,從而,是資料在棧上溢位,使其覆蓋正常的資料,從而引起漏洞與異常。

/

如果,溢位的資料覆蓋了ret地址,那麼函數可以跳轉到一個指定的函數,即上文的「attack」函數。

/

所以在這裡開始,找到attack函數的地址:

在這裡插入圖片描述
然後,只要將attack()的地址,輸入到文字的末尾即可。但是,要滿足其剛好能將ret的地址覆蓋,使函數跳轉異常,從而跳轉到指定的攻擊函數。
/

那麼,來計算一下,在文字中輸入多少個字元會剛剛覆蓋到「r」,處:

/

這裡檢視到這個資訊: [esp+10h] [ebp-18h] (如下圖)
/

5.分析怎麼實現棧溢位

在這裡插入圖片描述

由於記憶體棧區的地址由高地址向低地址增長,當4個位元組壓入棧幀時,即為 ESP=ESP-4, 有4個位元組彈出棧幀時, ESP=ESP+4.

ESP(extended stack point)是擴充套件棧指標暫存器,其存放地址指向這個棧幀的棧頂
/
EBP(extended base point)是擴充套件基址指標暫存器,其存放地址指向這個棧幀的棧底。

/
ESP與EBP之間是當前棧幀的空間。

上圖意為,從前棧底到str存放的位置還有18個位元組。即[ebp-18h]的含義。

其實從IDA中也能清晰看出來:

在這裡插入圖片描述
上圖中,可以看到變數str,password,fp存放在棧中的位置,可以看到上圖用紅色框框選的,有18個位元組,也就是上文的[ebp-18h],下面藍色框有10個位元組,即到r為止。
/
資料從上方加入,那我們只要在文字前加入(10+18)=28個位元組,就可以剛剛覆蓋到r處,r是執行完後要跳轉的函數地址,那我們在28個直接之後加入,攻擊函數attack()的地址即可。
/

在這裡插入圖片描述
將D槽的password.txt檔案拖入軟體「HxD」中,一種文字編輯軟體,notepad++也可。
輸入28個字母,之後將attack()的地址加入,即"00 40 13 50",但這裡是小端序。

這裡講一講:

6.小端序和大端序

位元組序即為多位元組物件儲存在記憶體中的位元組順序,有兩種不同的儲存方案:大端法和小端法。現代的處理器大多為雙端法,大小端都支援,可以設定稱大端法或者小端法。
/
大端序:(Big-endian):高位位元組存入低地址,低位位元組存入高地址
小端序:(Little-endian):低位位元組存入低地址,高位位元組存入高地址

7.繼續,執行結果,原理

一般x86位的CPU都為小端序:所以在編輯時將地址反著寫,寫作"50 13 40 00",
然後,點選「儲存」檔案。
/
再開啟編譯器,執行:
/
在這裡插入圖片描述
執行結果出現了TRY IT!,明顯這是attack()函數的內容,已經完成了棧溢位,使函數執行出了指定的內容,這就是用IDA實現的簡單的棧溢位攻擊實驗。
/
通過棧上資料的溢位,覆蓋了,正確的r返回地址,從而使函數跳轉出現失誤,或指向性的跳轉。可以加以利用。