緩衝區溢出屬於非常有名的漏洞之一,其大體含義為:緩衝區溢出是超出程序內存設定範圍,數據溢出後程序發生異常,黑客可以利用緩衝區溢出執行指定代碼,重寫棧中的返回地址(ret_Addr)內容來執行任意操作。
本文從棧的介紹、shellcode代碼示例、切入思路三個方面進行體系化介紹。
一、棧的介紹
棧是一種內存使用方式,採用LIFO(Last In,First Out,先進後出),像手槍的子彈夾一樣。
當調用func函數時,在跳轉至函數起始地址的瞬間,棧的形式如下圖:
基地址為內存高位,從後向前(向地址遞減方向)增長, $1、$2、$3為方法變量地址,ret_addr為main函數返回目標地址。
接下來 esp/rsp逐漸遞減,為函數內部的局部變量分配內存空間,a&buff為方法內變量,存儲形式如下圖:
這時,如果數據溢出,超過了原本分配給buff數組的內存空間,數組後面的ebp、ret_addr以及傳遞給函數的參數都會被溢出的數據覆蓋掉,如下圖:
一旦 ebp和ret_addr被覆蓋掉,將會引發嚴重的後果,ret_addr存放的為main函數返回目標地址,也就是說,如果覆蓋ret_addr,攻擊者就可以讓程序跳轉至任意地址,如果攻擊者事前準備一段shellcode,然後讓程序跳轉至這段代碼,也就相當於成功攻擊了”可執行任意代碼的漏洞“。
二、shellcode介紹
關於shellcode方面,簡單的shellcode代碼如下:
該代碼功能就是啟動/bin/sh。通過該代碼,我們可以將其轉換為彙編語言,通過gdb方式對程序進行調試,gdb指令常用操作如下:
r:程序運行;
b:設置斷點,加星號可傳遞地址;
c:在斷點處中斷後,繼續運行程序;
x/[數字]i:對指定數量的指令進行反彙編;
x/[數字]x:顯示指定長度數據;
x/[數字]s:以字符串形式顯示指定長度數據;
set:向寄存器或內存寫入;
q:退出;
通過對程序進行gdb調試,我們可清晰瞭解程序運行方式,如下圖:
上圖0X0000000000400550至558位置為execve方法的三個參數,倒序形式存放,我們在40055b位置設置斷點該位置為execve方法調用,當執行該方法時,我們通過r指令通過斷點使用x/8x指令,確認rsp內容是否包含“/bin/sh”。
瞭解系統執行原理後,可通過彙編語句形成代碼,代碼如下:
具體代碼解讀如下:
xor eax,eax //清空寄存器;
push eax //入棧
push 0x68732f2f //sh
push 0x6e69622f //bin
mov al, 0x3b //0x3b表示其系統調用號的十六進制,十進制為59,本系統execve的系統調用編號為59。需要根據自身系統來確定。
將彙編轉換成16進制
執行以下語句:
nasm -f elf testshell.asm
ld -m elf_i386 -o testshell testshell.o
最終形成16進制code碼,如下圖:
將上圖16進制代碼整合後,形成執行文件,
當我們執行該文件時,會出現段錯誤,是因為系統有保護機制,全局數據段shellcode不能被運行,即出現段錯誤。可安裝execstack,隨後執行:execstack -s 程序名,“故意”關掉 GCC 的堆棧段不可執行保護機制,便可執行成功,如下圖:
三、切入思路
通過第一章介紹,我們瞭解緩衝區溢出原理及如何利用該原理進行滲透。通過第二章我們實現了shellcode代碼編寫。如何利用緩衝區進行shellcode切入才是重重之重,一般我們不知道程序的返回地址,因此只能進行推測,我們可儘量在內存空間中填充NOP(0x90)指令(可通過gdb進行查看),然後將shellcode放在最後,這樣就可以提高shellcode執行的概率。
本文源自我之前在其它博客所寫文章,因之前內容不夠詳實,所以進行了再次編輯,通過本次再梳理使其內容更為豐富,具有更高的可讀性。通過以上內存溢出原理和簡單的shellcode,提供了一種代碼切入思路,在具體實施過程中難度還是非常大的。
閱讀更多 MR王峰 的文章