栈溢出笔记1.2 覆盖EIP
1.1節中我們說到可以利用棧溢出來破壞棧中原有的內容,這一節中,我們就來看看如何爭奪到返回地址(EIP),使得我們可以隨意控制它的值,這樣我們就可以控制程序。來看一個經典的程序:
這個程序的get_print函數中定義了一個大小為11個字節的數組,正常情況下我們的輸入應該最多為10個字符(還有一個\0結束符),而gets函數沒有明確定義輸入的大小,因此,我們可以輸入超過10個字符,從而造成棧溢出。如下,輸入10個‘A’,一切正常:?
?
圖8?
當我輸入11個‘A’時,雖然順利打印出來11個‘A’,但是VS2008報了如下錯:?
?
圖9
運行時錯誤檢查檢測到棧崩潰,這是Windows為抵抗棧溢出漏洞利用采用的措施。目前我們還不知道如何繞過,先去掉它,在工程屬性中,“C/C++”——“代碼生成”的“基本運行時檢查”選擇為默認值,然后重新編譯。?
?
圖10
修改后,輸入11個‘A’貌似是沒什么問題了,但是輸入12個‘A’的時候,又出來一個這樣的對話框:?
?
圖11
緩沖區溢出被檢查到了,這當然不是一個好消息。作為經典的漏洞,Windows自然有多種對付招式,這又是一種叫做棧Cookie的保護方式,可以檢查到棧溢出。同樣,先去掉它,在工程屬性中,“C/C++”——“代碼生成”的“緩沖區安全檢查”選擇為否(GS-, 見圖10),然后重新編譯。這一次,我們輸入一大串‘A’:
?
圖12
什么?VS2008又出現了彈窗?別緊張,這次是好消息。?
?
圖13
看到熟悉的0xC0000005,表明是訪問了不該訪問的地址。同時,0x41414141不就是“AAAA”嗎?這說明我們輸入的“AAAA”已經以某種方式被程序使用了,這果斷是好消息。
下面,用Immunity Debugger來看看究竟發生了什么。先找到函數get_print()的代碼,在 MOV EBP, ESP語句上下斷點:
?
圖14
然后運行到這里,查看棧內容:?
?
圖15
回想1.1中的內容,get_print沒有參數,因此0012FF14(當前ESP)處為保存的EBP,0012FF18(EBP+4)為返回地址(重要)。
下面兩句分配棧幀的代碼對棧的影響較大:
/*********************************************************/ MOV EBP, ESP SUB ESP, 4C /*********************************************************/- 1
- 2
- 3
- 4
分配了4C(76字節)大小的空間,因此,下面這段棧空間(get_print)是我們關注的內容:?
?
圖16
現在,定位到gets函數,我們關注的不是它的調用過程,而是參數,它位于棧上EBP-C的位置,因此,它緊鄰保存的EBP。也就是說,這個緩沖區下面是保存的EBP,再下面是保存的返回地址。這很重要,它決定我們需要輸入多少內容才能準確地改寫保存的返回地址(EIP)。
我們在gets函數之后設斷點,并輸入以下內容(16個A和4個B):
?
圖17
此時,查看棧內容:?
?
圖18
看到了嗎?保存的EBP被‘AAAA’覆蓋,保存的返回地址(EBP+4)被BBBB覆蓋。因為,我們知道局部變量的準確位置,因此,可以準確的知道需要多少字節來覆蓋返回地址的內容。?
這樣,我們就從程序手中爭奪了EIP,get_print()返回時,它將跳轉到0x42424242處執行,由于該地址不可訪問,因此會出現0xC0000005錯誤。后面,我們將給EIP寫入有意義的地址,從而執行我們自己的內容。
總結
以上是生活随笔為你收集整理的栈溢出笔记1.2 覆盖EIP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 高级IO函数之sendfil
- 下一篇: 第四百一十七天 how can I 坚持