緩衝區溢位漏洞--原理
0x00 緩衝區溢位概念
緩衝區溢位是指當計算機向緩衝區內填充資料位數時超過了緩衝區本身的容量溢位的資料覆蓋在合法資料上,
理想的情況是程式檢查資料長度並不允許輸入超過緩衝區長度的字元,但是絕大多數程式都會假設資料長度總是與所分配的儲存空間相匹配,這就為緩衝區溢位埋下隱患,作業系統所使用的緩衝區,又被稱為"堆疊"。在各個操作程序之間,指令會被臨時儲存在"堆疊"當中,"堆疊"也會出現緩衝區溢位。
0x01 緩衝區溢位原理
程式設計師通過往程式的緩衝區寫超出其長度的內容,造成緩衝區的溢位,從而破壞程式的堆疊,使程式轉而執行其它指令,以達到攻擊的目的。造成緩衝區溢位的原因是程式中沒有仔細檢查使用者輸入的引數。例如下面程式:
void function(char *str) { char buffer[16]; strcpy(buffer,str); }
上面的strcpy()將直接把str中的內容copy到buffer中。這樣只要str的長度大於16,就會造成buffer的溢位,使程式執行出錯。存在象strcpy這樣的問題的標準函式還有strcat(),sprintf(),vsprintf(),gets(),scanf()等。
當然,隨便往緩衝區中填東西造成它溢位一般只會出現“分段錯誤”(Segmentation fault),而不能達到攻擊的目的。最常見的手段是通過製造緩衝區溢位使程式執行一個使用者shell,再通過shell執行其它命令。如果該程式屬於root且有suid(Set User ID,)許可權的話,攻擊者就獲得了一個有root許可權的shell,可以對系統進行任意操作了。
0x02 緩衝區溢位漏洞攻擊方式
緩衝區溢位漏洞可以使任何一個有黑客技術的人取得機器的控制權甚至是最高許可權。一般利用緩衝區溢位漏洞攻擊root程式,大都通過執行類似“exec(sh)”的執行程式碼來獲得root 的shell。黑客要達到目的通常要完成兩個任務,就是在程式的地址空間裡安排適當的程式碼和通過適當的初始化暫存器和儲存器,讓程式跳轉到安排好的地址空間執行。
1)在程式的地址空間裡安排適當的程式碼
在程式的地址空間裡安排適當的程式碼往往是相對簡單的。如果要攻擊的程式碼在所攻擊程式中已經存在了,那麼就簡單地對程式碼傳遞一些引數,然後使程式跳轉到目標中就可以完成了。攻擊程式碼要求執行“exec(‘/bin/sh’)”,而在libc庫中的程式碼執行“exec(arg)”,其中的“arg”是個指向字串的指標引數,只要把傳入的引數指標修改指向“/bin/sh”,然後再跳轉到libc庫中的響應指令序列就可以了。當然,很多時候這個可能性是很小的,那麼就得用一種叫“植入法”的方式來完成了。
當向要攻擊的程式裡輸入一個字串時,程式就會把這個字串放到緩衝區裡,這個字串包含的資料是可以在這個所攻擊的目標的硬體平臺上執行的指令序列。緩衝區可以設在:堆疊(自動變數)、堆(動態分配的)和靜態資料區(初始化或者未初始化的資料)等的任何地方。也可以不必為達到這個目的而溢位任何緩衝區,只要找到足夠的空間來放置這些攻擊程式碼就夠了。
2)控制程式轉移到攻擊程式碼的形式
緩衝區溢位漏洞攻擊都是在尋求改變程式的執行流程,使它跳轉到攻擊程式碼,最為基本的就是溢位一個沒有檢查或者其他漏洞的緩衝區,這樣做就會擾亂程式的正常執行次序。通過溢位某緩衝區,可以改寫相近程式的空間而直接跳轉過系統對身份的驗證。原則上來講攻擊時所針對的緩衝區溢位的程式空間可為任意空間。但因不同地方的定位相異,所以也就帶出了多種轉移方式。
(1)Function Pointers(函式指標)
在程式中,“void (* foo) ( )”聲明瞭個返回值為“void” Function Pointers的變數“foo”。Function Pointers可以用來定位任意地址空間,攻擊時只需要在任意空間裡的Function Pointers鄰近處找到一個能夠溢位的緩衝區,然後用溢位來改變Function Pointers。當程式通過Function Pointers呼叫函式,程式的流程就會實現。
(2)Activation Records(啟用記錄)
當一個函式呼叫發生時,堆疊中會留駐一個Activation Records,它包含了函式結束時返回的地址。執行溢位這些自動變數,使這個返回的地址指向攻擊程式碼,再通過改變程式的返回地址。當函式呼叫結束時,程式就會跳轉到事先所設定的地址,而不是原來的地址。這樣的溢位方式也是較常見的。
3)植入綜合程式碼和流程控制
常見的溢位緩衝區攻擊類是在一個字串裡綜合了程式碼植入和Activation Records。攻擊時定位在一個可供溢位的自動變數,然後向程式傳遞一個很大的字串,在引發緩衝區溢位改變Activation Records的同時植入程式碼(權因C在習慣上只為使用者和引數開闢很小的緩衝區)。植入程式碼和緩衝區溢位不一定要一次性完成,可以在一個緩衝區內放置程式碼(這個時候並不能溢位緩衝區),然後通過溢位另一個緩衝區來轉移程式的指標。這樣的方法一般是用於可供溢位的緩衝區不能放入全部程式碼時的。如果想使用已經駐留的程式碼不需要再外部植入的時候,通常必須先把程式碼做為引數。在libc(熟悉C的朋友應該知道,現在幾乎所有的C程式連線都是利用它來連線的)中的一部分程式碼段會執行“exec(something)”,當中的something就是引數,使用緩衝區溢位改變程式的引數,然後利用另一個緩衝區溢位使程式指標指向libc中的特定的程式碼段。
0x03 實驗分析
1) main函式在呼叫f函式前,首先將參入的引數壓入棧中;
2) 接著,將當前程式執行的下一個的位置EIP加入棧中,後面f函式返回時用;
3) 進入f函式,f函式首先將當前的EBP壓入棧中,接著mov esp, ebp(將EBP指向當前的棧頂),接著以EBP為基礎構建自己的函式幀結構。函式幀結構中包含當前函式的區域性變數(攻擊的示例程式的buffer變數及在這裡面)
4) 在f函式執行完成後,會將棧中的EBP值彈出,恢復到EBP暫存器中,還原ESP暫存器,接著彈出EIP變數,程式根據EIP變數指向的位置接著執行main函式後面的程式部分。
JMP ESP原理:
函式返回時執行指令:
mov esp,ebp;
pop ebp;
ret;
mov esp ,ebp 將esp指向函式返回地址
pop ebp 此時esp棧頂上移+4,esp為返回地址+4
ret 相當於pop EIP
JMP ESP命令地址填充在ESP位置,函式執行並返回,跳轉到ESP,然後執行ESP裡的JMP ESP命令,該命令跳轉到原ESP地址+4的地方,也就是後面的shellcode
構造shellcode的思想就是使用payload = 填充偏移+ESP(也就是返回地址+4的地方,填寫JMP ESP命令地址)+shellcode
0x04 緩衝區概念
緩衝區在系統中的表現形式是多樣的,高階語言定義的變數、陣列、結構體等在執行時可以說都是儲存在緩衝區內的,因此所謂緩衝區可以更抽象地理解為一段可讀寫的記憶體區域,緩衝區攻擊的最終目的就是希望系統能執行這塊可讀寫記憶體中已經被蓄意設定好的惡意程式碼。按照馮·諾依曼儲存程式原理,程式程式碼是作為二進位制資料儲存在記憶體的,同樣程式的資料也在記憶體中,因此直接從記憶體的二進位制形式上是無法區分哪些是資料哪些是程式碼的,這也為緩衝區溢位攻擊提供了可能。
圖1是程序地址空間分佈的簡單表示。程式碼儲存了使用者程式的所有可執行程式碼,在程式正常執行的情況下,程式計數器(PC指標)只會在程式碼段和作業系統地址空間(核心態)內定址。資料段記憶體儲了使用者程式的全域性變數,文字池等。棧空間儲存了使用者程式的函式棧幀(包括引數、區域性資料等),實現函式呼叫機制,它的資料增長方向是低地址方向。堆空間儲存了程式執行時動態申請的記憶體資料等,資料增長方向是高地址方向。除了程式碼段和受作業系統保護的資料區域,其他的記憶體區域都可能作為緩衝區,因此緩衝區溢位的位置可能在資料段,也可能在堆、棧段。如果程式的程式碼有軟體漏洞,惡意程式會“教唆”程式計數器從上述緩衝區內取指,執行惡意程式提供的資料程式碼!
原文連結:https://blog.csdn.net/weixin_41644777/article/details/79953062
原文連結:https://blog.csdn.net/qq_17204441/article/details/90105170
https://www.cnblogs.com/fanzhidongyzby/archive/2013/08/10/3250405.html