• 沒有找到結果。

堆疊緩衝區溢位攻擊原理

第二章、 背景知識

2.1. 堆疊緩衝區溢位攻擊原理

在現行的 x86 及 x64 系統下所有的區域變數都是存放在堆疊中,等待其運作 函式存取,緩衝區故而得名。當緩衝區資料越界時就有可能影響到其他資料的 完整性甚至可能更動整個程式控制流程,圖1 為經典的堆疊緩衝區溢位範例 [6]:

圖 1、堆疊緩衝區溢位攻擊

很容易就可以從程式碼得出,當使用者輸入超過20 個字元時,程式執行將 會出現超出預期的行為,透過詳細分析與安排之後,便可以將這些原本是不可 預期的程式錯誤行為轉換為任意命令運行(Arbitrary Command Execution, ACE)甚 至權限提昇(Privilege Escalation)等行為。

2.1.1. 呼叫慣例

呼叫慣例(Calling convention)是函式呼叫者(Caller)以及被呼叫者(Callee)之間約 定的參數傳遞及堆疊平衡慣例,確保函式可以被正常的呼叫並回傳結果。通常 不同的作業系統及編譯器之間都有相異的呼叫慣例,或是有特定需求的架構、

4

及程式語言也會有相異的呼叫慣例[7]。

GCC on Linux x86 架構使用的呼叫慣例是 cdecl,其特點為所有的參數會被 由右至左放置到堆疊中,並且使用累加暫存器(AX)來傳遞函式的結果,並且都 是由呼叫者(Caller)來準備與收回被呼叫者(Caller)所需要使用到的堆疊空間。

2.1.2. x86 組合語言指令

圖 2、反組譯結果

圖 2 為圖 1 反組譯結果並擷取的主要程式片段,只需要了解 call、ret 兩個 指令即可:

 call 指令可分為兩個步驟:

1. 將下一行指令存到堆疊頂端 2. 跳往欲呼叫的函式位址

 ret 指令的作用為將堆疊頂端的資料放入指令指標暫存器。

2.1.3. 函數組成

在x86 與 x64 的結構下,組合語言層面的函數組成分為三個部分分別為:

Prologue、Body、Epilogue,以圖 2 為例,前四行就屬於 Prologue 的範圍範

5

疇,其作用在於將前一個 stack frame 的基底指標儲存在堆疊中,並創造出區 域變數會使用的空間大小; Body 則為函數的主體,主要執行函數本身的功能;

Epilogue 則負責與 Prologue 相反的事務,並加上最後一行 ret 將指標暫存器 指向堆疊頂端的位址指引CPU 繼續執行[8][9]。

2.1.4. Stack Frame

我們將xSP 到 xBP 的範圍稱為 stack frame,裡面儲存著該函數的區域變數,以 便於CPU 使用基底暫存器(base register)加上偏移值(offset)來取得其位址。通常 每個函數都會有自己的 stack frame,其建立及銷毀也都依賴位於函數首部及尾 部的Prologue 與 Epilogue。

2.1.5. 堆疊佈局

圖 3、輸入資料之前

圖 4、輸入 AAAAAAAABBBBBBBB 之後

由圖3 與圖 4 的差異可得知,在 Linux x86_64 的環境下堆疊的資料寫入 是用little endian 的方式由低位址往高位址覆蓋[10]。同理,緩衝區溢位攻擊的 方向也應相同,所以緩衝區溢位攻擊,並無法影響到更低位址所儲存的資料。

6

2.1.6. 攻擊實例

下面為一個可被 Stack-based Bof 攻擊的實例程式碼,後面章節的攻擊範例,都 以這段程式碼為目標:

1. #include <stdio.h>

2. void admin() { 針對輸入做任何的條件判斷或是運算,但是此程式卻存在弱點 (Vulnerability) 並且為可利用(Exploitable) 的狀態。經過計算並輸入惡意資料便可成功執行危 險函數 admin,這也驗證了其指令指標(IP, Instruction Pointer) 可被輸入的資料 給汙染,並且對系統產生任意的行為。

7

圖 5、範例程式反組譯結果

圖 5 為範例程式主要存在弱點之函數 greeting 的反組譯結果,顯而易見的 在組語第三行將堆疊空出0x10 也就是 16 位元組的空間,而第四行則是將寫入 的位址標明為RBP-0x4 開始,這樣便滿足 C 原始碼所宣告的 4 個位元組,又程 式邏輯上並沒有對gets 函式輸入做任何的限制,導致當輸入的資料超過 0x10 時,堆疊中的其他資料就會被覆寫。

圖 6、堆疊變化示意

圖 6 為 gets 執行後接收到 ABCD 的示意圖,可以明顯看出資料的寫入方 向為由上往下並且以little endian 的方式寫入堆疊區中,所以當資料超過 4 個位 元組時會首先覆蓋到saved-RBP 也就是等待函數還原後 RBP 指向的位址,通常 這個區塊被覆寫以後不會有立即的影響,在程式沒有使用基於RBP 位址的偏移 存取時而產生錯誤之前,程式仍然可以正常執行。

8

在Epilogue 清除堆疊空間之後,saved-RIP 會剛好處於 RSP 所指向的位 址,通常這個時候下一個指令便是ret,攻擊者便可透過資料覆寫的方式,改寫 saved-RIP,如此一來便可以控制 CPU 執行指令的方向。然而為了展示方便,

程式碼中已有一個名為admin 的危險函式做為攻擊者的目標,又因為一般情況 下編譯器不會幫你加上任何的緩解策略選項,所以函數的程式碼位址在每次執 行時期(Runtime)都是相同的。

總結來說只要覆蓋前面12 個位元組最後加上 admin 函數的位址

\x40\x06\x00(0x400600),便可將程式的執行流程劫持(Hijack)並導向 admin 函 式。 下還是可能透過以下情況被攻擊:程式碼重用攻擊(CRA, Code Reuse Attack)技 巧如ROP(Return-Oriented Programming)[11][12][13][14][15][16]或是其他類似的 攻擊:SROP (Sigreturn-Oriented Programming)[17]、JOP(Jump-Oriented

Programming)[18]、SOP(String-Oriented Programming)[19]、Data-Only Attack [20]等等。

2.2.1. 位址空間配置隨機載入 (ASLR)

作業系統提供的緩解方法包括ASLR 及 DEP。ASLR 的概念是程式執行時堆 疊、VDSO(Virtual Dynamically-linked Shared Object)以及載入的函式庫等,位於 資料區段的資料在記憶體中的位址,在每次運行時都會不同,使得程式運行狀

相關文件