緩衝區溢出(Buffer Overflow)是計算機安全領域內既經典而又古老的話題。隨着計算機系統安全性的增強,傳統的緩衝區溢出攻擊方式可能變得再也不奏效,相應的介紹緩衝區溢出原理的資料也變得「大衆化」起來。linux
緩衝區溢出的含義是爲緩衝區提供了多於其存儲容量的數據,就像往杯子裏倒入了過量的水同樣。一般狀況下,緩衝區溢出的數據只會破壞程序數據,形成意外終止。可是若是有人精心構造溢出數據的內容,那麼就有可能得到系統的控制權!若是說用戶(也多是黑客)提供了水——緩衝區溢出攻擊的數據,那麼系統提供了溢出的容器——緩衝區。vim
緩衝區在系統中的表現形式是多樣的,高級語言定義的變量、數組、結構體等在運行時能夠說都是保存在緩衝區內的,所以所謂緩衝區能夠更抽象地理解爲一段可讀寫的內存區域,緩衝區攻擊的最終目的就是但願系統能執行這塊可讀寫內存中已經被蓄意設定好的惡意代碼。按照馮·諾依曼存儲程序原理,程序代碼是做爲二進制數據存儲在內存的,一樣程序的數據也在內存中,所以直接從內存的二進制形式上是沒法區分哪些是數據哪些是代碼的,這也爲緩衝區溢出攻擊提供了可能。數組
圖1 進程地址空間分佈安全
圖1是進程地址空間分佈的簡單表示。代碼存儲了用戶程序的全部可執行代碼,在程序正常執行的狀況下,程序計數器(PC指針)只會在代碼段和操做系統地址空間(內核態)內尋址。數據段內存儲了用戶程序的全局變量,文字池等。棧空間存儲了用戶程序的函數棧幀(包括參數、局部數據等),實現函數調用機制,它的數據增加方向是低地址方向。堆空間存儲了程序運行時動態申請的內存數據等,數據增加方向是高地址方向。除了代碼段和受操做系統保護的數據區域,其餘的內存區域均可能做爲緩衝區,所以緩衝區溢出的位置可能在數據段,也可能在堆、棧段。若是程序的代碼有軟件漏洞,惡意程序會「教唆」程序計數器從上述緩衝區內取指,執行惡意程序提供的數據代碼!本文分析並實現棧溢出攻擊方式。函數
計算機程序通常都會使用到一些內存,這些內存或是程序內部使用,或是存放用戶的輸入數據,這樣的內存通常稱做緩衝區。溢出是指盛放的東西超出容器容量而溢出來了,在計算機程序中,就是數據使用到了被分配內存空間以外的內存空間。而緩衝區溢出,簡單的說就是計算機對接收的輸入數據沒有進行有效的檢測(理想的狀況是程序檢查數據長度並不容許輸入超過緩衝區長度的字符),向緩衝區內填充數據時超過了緩衝區自己的容量,而致使數據溢出到被分配空間以外的內存空間,使得溢出的數據覆蓋了其餘內存空間的數據。學習
1.先cp一個一樣的可執行文件,將本來的pwn1做爲備份。spa
2.反彙編,瞭解程序的基本功能。用指令objdump反彙編20145211操作系統
誠如劉老師上課講的那樣,第一列爲內存地址,第二列爲機器指令,第三列爲彙編指令。3d
先看main函數反彙編的第4行,"call 8048491 "是彙編指令,是說這條指令將調用位於地址8048491處的foo函數;其對應機器指令爲"e8 d7ffffff",e8即跳轉之意。原本正常流程,此時此刻EIP的值應該是下條指令的地址,即80484ba,但一解釋e8這條指令呢,CPU就會轉而執行 "EIP + d7ffffff"這個位置的指令。"d7ffffff"是補碼,表示-41,41=0x29,80484ba +d7ffffff= 80484ba-0x29正好是8048491這個值(foo函數調用入口)。main函數調用foo,對應機器指令爲" e8 d7ffffff",那咱們想讓它調用getShell,只要修改"d7ffffff"爲,"getShell-80484ba"對應的補碼就行。用Windows計算器,直接 47d-4ba就能獲得補碼,是c3ffffff。指針
下面修改可執行文件,將其中的call指令的目標地址由d7ffffff變爲c3ffffff。
3.vi20145211,並將其調成16進制顯示,用指令「:%!xxd」
4.查詢並修改e8 d7,用指令「/e8 d7」;a鍵進入編輯模式,將d7改成c3。
5.轉成原格式保存退出,用指令「:%!xxd -r」,再次執行20145211
能夠發現咱們已經能夠隨心所欲,隨心所欲,隨心所欲……
6.再次反彙編驗證機器指令
簡單介紹一下:
1.open file:20145211
2.search 「e8」,so many;search "d7" instead,and substitute with "c3"
1.再次cp一個20145211
2.進入gdb調試,輸入一段神奇的字串1111111122222222333333334444444455555555
;觀察一下各寄存器的值
3.此時eip寄存器中的值爲0x35353535,即5555的ASCII碼。eip寄存器的值是保存程序下一步所要執行指令的地址,此處咱們能夠看出原本應返回到foo函數的返回地址已被"5555"覆蓋
4.將輸入字符串的「55555555」改爲「12345678」,以便進一步觀察修改的地方。
此時寄存器eip的值,如上圖「0x34333231 0x34333231」,換算成ASCⅡ碼恰好是1234。也就是說若是輸入字符串1111111122222222333333334444444412345678,那 1234 那四個數最終會覆蓋到堆棧上的返回地址,進而CPU會嘗試運行這個位置的代碼。那隻要把這四個字符替換爲 getShell 的內存地址,輸給20145211,20145211就會運行getShell。
5.獲取機器字節序存儲所採起的方式
在輸入字符串的地方0x804847d處設置斷點,查其eip 0x804847d 0x804847d,能夠發現是大端模式;因沒法經過鍵盤輸入\x7d\x84\x04\x08這樣的16進制值,因此只能本身生成,並將輸出重定向到input中,用「xxd input」檢查是否操做成功;最後將input的輸入,經過管道符「|」,做爲pwn1的輸入,執行獲得結果