堆溢出

其實堆溢出與格式串溢出特像,就是“一個format strings“的bug可以使往任何數據寫到任何地方。

現在堆溢出的研究有點升溫,暴露出來的堆溢出漏洞也越來越多,所以就有必要研究有效的堆溢出攻擊方法了。由於堆溢出只是緩衝區溢出的一種形式,原理已經介紹得比較多,也比較簡單,所以就不再做這方面的介紹。
一、堆溢出後的後果;
現在的系統管理堆,為了查詢的高效快速,一般都使用的雙向鍊表結構。我們來看雙向鍊表管理的時候的刪除操作。*a,*b,*p1,*p2,*c, *d都是指針,考慮雙向鍊表,a,b--->p1,p2--->c,d,其中由雙向鍊表有*b=p1,*p1=a,*p2=c。如果是空閒記憶體鍊表,那么申請使用p1、p2指向的記憶體,或者如果是使用記憶體鍊表,釋放p1、p2指向的記憶體,都會從這個鍊表中刪除p1,p2。刪除後的鍊表是a,b --->c,d,應該有記憶體改寫操作:*b=c,*c=a。這時代碼是經過鍊表檢索從a,b得到的p1,p2,一般為了高效等就不會記憶a,b,因為雙向鍊表就是為了從一個結點可以方便的得到上級和下級結點。所以那兩條記憶體操作都將會轉換成p1、p2相關的操作。根據前面得到的信息,經過簡單的代換就可以得到我們需要的代碼:
*b=p1,*p1=a,*p2=c,b=a+1
*b=c--->*(a+1)=c--->*(*p1+1)=*p2
*c=a--->*(*p2)=*p1
兩次指針,可能看起來不是很習慣,再把*p1記成p1,*p2記成p2,那么就有:
*p2=p1
*(p1+1)=p2
這就是堆溢出後導致的兩個寫記憶體操作,以後考慮堆溢出,不考慮細節的話基本上就可以用這兩條代碼代替。這時的p1、p2已經不是指那鍊表的位置了,而是指裡面的內容。
二、利用。
要利用堆溢出,就考慮上面總結的兩條代碼的利用就是了。
1、改寫記憶體參數,直接利用。可以改寫重要變數,還有一個字元串的長度,格式串等,讓起改寫後再產生別的溢出等。這要改寫一般只能改寫數據段裡面的東西,因為這位置相對固定並且可寫。
2、改寫函式指針性質的調用入口等。這個要寫遠程通用程式的難點還是shellcode的定位問題,只要有一個定位shellcode的辦法,基本上就可以有一種堆溢出的利用辦法。
(1)、unix等系統下面的s位程式的本地溢出。這個應該算比較簡單好利用的一個套用了。shellcode通過環境塊等傳遞,就可以比較精確的找到shellcode的位置。這樣只需要改寫一個函式指針內容,讓其指向shellcode就可以了。
(2)、可以設定對一些可用於傳遞的shellcode域的讀寫斷點,發現如果上面兩條指令執行完後有如:
lea ebx,[EBP+0xxx]
push ebx
call dword ptr [0xxxxxxxxx]
這樣的代碼,並且那ebx指向可傳遞shellcode的域,就能方便的利用,這樣兩個指針就可以分別選取0xxxxxxxxx和一個具有jmp ebx功能的地址。注意可能會要考慮前面兩條指令或者那鍊表操作時候可能發生的異常。
(3)、利用p1、p2自身信息定位。
能夠覆蓋p1、p2,一般p1、p2前面會有一段空間能夠控制,如果覆蓋的長度可以控制。可以考慮保留p2的高位,改寫其低位讓起指向 shellcode。這個要注意這時shllcode的前面4位元組會被調用函式入口地址覆蓋,所以不是所有會調用的函式入口都可以用。
(4)、利用SEH指針。
其實那雙向鍊表經常是a,b--->p1,p2--->a,b的形式,所以把SEH鏈首fs:0,位置一般在ds:7ffxxxxx,同一系統比較固定覆蓋,然後利用p2原來的值。這個有很多問題,跳
到p1後,p1不是可控制代碼,還有系統的SEH處理程式會檢測fs:0首指針,如果不是指向堆疊位置,拒絕執行。主要是這個思路看能不能有別的辦法。這個又考慮了覆蓋fs:0首指針的低位元組,這樣異常結構鍊表位置就發生了變化,如果指向的另一塊堆棧位置能夠控制,就可以利用偽造異常鍊表的辦法獲得控制。其實單位元組的溢出覆蓋ebp低位元組的利用原理也是差不多。而堆疊裡面,往往會有動態BUFF拷貝過去的數據可以控制,所以這個要求也是容易辦到。現在確定的是這個指針的位置不是固定的,有一定的變化範圍。可能是0x7ff93000 、0x7ff9b000這樣的值,但變化不是多大。
(5)、改寫指針,跳轉到ret 0xxxxx這樣的指令處,通過改變堆疊指針的辦法,利用堆疊裡面的可控制數據得到控制。
三、實際套用例子。
.asp的分塊編碼堆溢出,其實這個漏洞不應該叫分塊編碼漏洞,因為漏洞原因不在 於分塊編碼。
上面(2)、(3) 基本上都是可行的,但因為.asp的特殊之處,又使得上面的(2)、(3)對於這個漏洞不好使用。
1、對於(2),由於.asp的那段溢出沒安裝好異常處理程式,所以在那鍊表結構的處理過程中一般會發生異常,從而程式結束。如果精心構造覆蓋 p1、p2和用於鍊表處理的標記、長度的數據,可以不會發生異常,但處理完後馬上又被別的不容易控制的數據覆蓋,再次導致異常。
這個現在在win2000+sp2的wam.dll裡面找到一處可以利用的代碼,但只能是下次重新連線才能得到控制。
2、對於(3),由於申請的0位元組記憶體,加上記憶體管理的8位元組對齊,可以得到8個位元組,再除去兩條代碼寫記憶體浪費4位元組,只剩下4位元組,所以基本上不能用。利用另一個方式,可以申請大量記憶體,但這時只能是覆蓋0xc000位元組(問題在這),因為記憶體管理的8位元組對齊,不可能只覆蓋p2的低位元組。
3、對於(4),已經寫出利用程式。
4、對於(5),顯然是可利用的,並且可能會寫得比較通用。現在需要的是找一個通用的指針位置,就是沒有語言版本、sp包的問題,所有的都通用。否則就需要有版本參數。
外面發布的代碼。基本上都是利用覆蓋一個異常處理句柄入口地址(有版本問題),再加上猜測的shellcode地址,所以通用性大打折扣。其實一般堆溢出,利用上面的(2)、(3)還是可以做得比較通用的.

相關詞條

相關搜尋

熱門詞條

聯絡我們